mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-29 16:47:56 +00:00
Merge branch 'mc-1.20.x' into mc-1.21.x
This commit is contained in:
@@ -12,7 +12,7 @@ neogradle.subsystems.conventions.runs.enabled=false
|
|||||||
|
|
||||||
# Mod properties
|
# Mod properties
|
||||||
isUnstable=true
|
isUnstable=true
|
||||||
modVersion=1.115.1
|
modVersion=1.116.0
|
||||||
|
|
||||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||||
mcVersion=1.21.1
|
mcVersion=1.21.1
|
||||||
|
@@ -69,7 +69,7 @@ ideaExt = "1.1.7"
|
|||||||
illuaminate = "0.1.0-83-g1131f68"
|
illuaminate = "0.1.0-83-g1131f68"
|
||||||
lwjgl = "3.3.3"
|
lwjgl = "3.3.3"
|
||||||
minotaur = "2.8.7"
|
minotaur = "2.8.7"
|
||||||
modDevGradle = "2.0.78"
|
modDevGradle = "2.0.95"
|
||||||
nullAway = "0.12.7"
|
nullAway = "0.12.7"
|
||||||
shadow = "8.3.1"
|
shadow = "8.3.1"
|
||||||
spotless = "7.0.2"
|
spotless = "7.0.2"
|
||||||
|
676
package-lock.json
generated
676
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||||
"@rollup/plugin-typescript": "^12.0.0",
|
"@rollup/plugin-typescript": "^12.0.0 && <12.1.3",
|
||||||
"@rollup/plugin-url": "^8.0.1",
|
"@rollup/plugin-url": "^8.0.1",
|
||||||
"@swc/core": "^1.3.92",
|
"@swc/core": "^1.3.92",
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^24.0.0",
|
||||||
"lightningcss": "^1.22.0",
|
"lightningcss": "^1.22.0",
|
||||||
"preact-render-to-string": "^6.2.1",
|
"preact-render-to-string": "^6.2.1",
|
||||||
"rehype": "^13.0.0",
|
"rehype": "^13.0.0",
|
||||||
|
@@ -205,8 +205,10 @@
|
|||||||
"item.computercraft.treasure_disk": "Disketa",
|
"item.computercraft.treasure_disk": "Disketa",
|
||||||
"itemGroup.computercraft": "ComputerCraft",
|
"itemGroup.computercraft": "ComputerCraft",
|
||||||
"tag.item.computercraft.computer": "Počítače",
|
"tag.item.computercraft.computer": "Počítače",
|
||||||
|
"tag.item.computercraft.disks": "Disky",
|
||||||
"tag.item.computercraft.dyeable": "Obarvitelné předměty",
|
"tag.item.computercraft.dyeable": "Obarvitelné předměty",
|
||||||
"tag.item.computercraft.monitor": "Monitory",
|
"tag.item.computercraft.monitor": "Monitory",
|
||||||
|
"tag.item.computercraft.pocket_computers": "Kapesní počítače",
|
||||||
"tag.item.computercraft.turtle": "Roboti",
|
"tag.item.computercraft.turtle": "Roboti",
|
||||||
"tag.item.computercraft.turtle_can_place": "Roboty-umístitelné předměty",
|
"tag.item.computercraft.turtle_can_place": "Roboty-umístitelné předměty",
|
||||||
"tag.item.computercraft.wired_modem": "Drátové modemy",
|
"tag.item.computercraft.wired_modem": "Drátové modemy",
|
||||||
|
@@ -177,6 +177,7 @@
|
|||||||
"item.computercraft.treasure_disk": "Diskette",
|
"item.computercraft.treasure_disk": "Diskette",
|
||||||
"itemGroup.computercraft": "ComputerCraft",
|
"itemGroup.computercraft": "ComputerCraft",
|
||||||
"tag.item.computercraft.computer": "Computer",
|
"tag.item.computercraft.computer": "Computer",
|
||||||
|
"tag.item.computercraft.dyeable": "Färbbare Elemente",
|
||||||
"tag.item.computercraft.monitor": "Monitore",
|
"tag.item.computercraft.monitor": "Monitore",
|
||||||
"tag.item.computercraft.turtle": "Turtles",
|
"tag.item.computercraft.turtle": "Turtles",
|
||||||
"tag.item.computercraft.wired_modem": "Verkabelte Modems",
|
"tag.item.computercraft.wired_modem": "Verkabelte Modems",
|
||||||
|
@@ -205,8 +205,10 @@
|
|||||||
"item.computercraft.treasure_disk": "Disco Floppy",
|
"item.computercraft.treasure_disk": "Disco Floppy",
|
||||||
"itemGroup.computercraft": "ComputerCraft",
|
"itemGroup.computercraft": "ComputerCraft",
|
||||||
"tag.item.computercraft.computer": "Computer",
|
"tag.item.computercraft.computer": "Computer",
|
||||||
|
"tag.item.computercraft.dyeable": "Oggetti colorabili",
|
||||||
"tag.item.computercraft.monitor": "Monitor",
|
"tag.item.computercraft.monitor": "Monitor",
|
||||||
"tag.item.computercraft.turtle": "Tartarughe",
|
"tag.item.computercraft.turtle": "Tartarughe",
|
||||||
|
"tag.item.computercraft.turtle_can_place": "Oggetti piazzabili da tartarughe",
|
||||||
"tag.item.computercraft.wired_modem": "Modem cablati",
|
"tag.item.computercraft.wired_modem": "Modem cablati",
|
||||||
"tracking_field.computercraft.avg": "%s (media)",
|
"tracking_field.computercraft.avg": "%s (media)",
|
||||||
"tracking_field.computercraft.computer_tasks.name": "Attività",
|
"tracking_field.computercraft.computer_tasks.name": "Attività",
|
||||||
|
@@ -205,8 +205,10 @@
|
|||||||
"item.computercraft.treasure_disk": "フロッピーディスク",
|
"item.computercraft.treasure_disk": "フロッピーディスク",
|
||||||
"itemGroup.computercraft": "ComputerCraft",
|
"itemGroup.computercraft": "ComputerCraft",
|
||||||
"tag.item.computercraft.computer": "コンピューター",
|
"tag.item.computercraft.computer": "コンピューター",
|
||||||
|
"tag.item.computercraft.disks": "ディスク",
|
||||||
"tag.item.computercraft.dyeable": "染色可能なアイテム",
|
"tag.item.computercraft.dyeable": "染色可能なアイテム",
|
||||||
"tag.item.computercraft.monitor": "モニター",
|
"tag.item.computercraft.monitor": "モニター",
|
||||||
|
"tag.item.computercraft.pocket_computers": "ポケットコンピューター",
|
||||||
"tag.item.computercraft.turtle": "タートル",
|
"tag.item.computercraft.turtle": "タートル",
|
||||||
"tag.item.computercraft.turtle_can_place": "タートルが設置可能なアイテム",
|
"tag.item.computercraft.turtle_can_place": "タートルが設置可能なアイテム",
|
||||||
"tag.item.computercraft.wired_modem": "有線モデム",
|
"tag.item.computercraft.wired_modem": "有線モデム",
|
||||||
|
@@ -92,6 +92,7 @@
|
|||||||
"item.computercraft.printed_pages": "Wydrukowane Strony",
|
"item.computercraft.printed_pages": "Wydrukowane Strony",
|
||||||
"item.computercraft.treasure_disk": "Dyskietka",
|
"item.computercraft.treasure_disk": "Dyskietka",
|
||||||
"itemGroup.computercraft": "ComputerCraft",
|
"itemGroup.computercraft": "ComputerCraft",
|
||||||
|
"tag.item.computercraft.turtle_can_place": "Przedmioty stawialne przez Żółwia",
|
||||||
"upgrade.computercraft.speaker.adjective": "Hałaśliwy",
|
"upgrade.computercraft.speaker.adjective": "Hałaśliwy",
|
||||||
"upgrade.computercraft.wireless_modem_advanced.adjective": "Enderowy",
|
"upgrade.computercraft.wireless_modem_advanced.adjective": "Enderowy",
|
||||||
"upgrade.computercraft.wireless_modem_normal.adjective": "Bezprzewodowy",
|
"upgrade.computercraft.wireless_modem_normal.adjective": "Bezprzewodowy",
|
||||||
|
@@ -205,8 +205,10 @@
|
|||||||
"item.computercraft.treasure_disk": "Disket",
|
"item.computercraft.treasure_disk": "Disket",
|
||||||
"itemGroup.computercraft": "ComputerCraft",
|
"itemGroup.computercraft": "ComputerCraft",
|
||||||
"tag.item.computercraft.computer": "Bilgisayarlar",
|
"tag.item.computercraft.computer": "Bilgisayarlar",
|
||||||
|
"tag.item.computercraft.disks": "Diskler",
|
||||||
"tag.item.computercraft.dyeable": "Boyanabilir eşyalar",
|
"tag.item.computercraft.dyeable": "Boyanabilir eşyalar",
|
||||||
"tag.item.computercraft.monitor": "Monitörler",
|
"tag.item.computercraft.monitor": "Monitörler",
|
||||||
|
"tag.item.computercraft.pocket_computers": "Cep Bilgisayarları",
|
||||||
"tag.item.computercraft.turtle": "Turtlelar",
|
"tag.item.computercraft.turtle": "Turtlelar",
|
||||||
"tag.item.computercraft.turtle_can_place": "Kaplumbağa-yerleştirilebilir eşyalar",
|
"tag.item.computercraft.turtle_can_place": "Kaplumbağa-yerleştirilebilir eşyalar",
|
||||||
"tag.item.computercraft.wired_modem": "Kablolu modemler",
|
"tag.item.computercraft.wired_modem": "Kablolu modemler",
|
||||||
|
@@ -205,8 +205,10 @@
|
|||||||
"item.computercraft.treasure_disk": "软盘",
|
"item.computercraft.treasure_disk": "软盘",
|
||||||
"itemGroup.computercraft": "ComputerCraft",
|
"itemGroup.computercraft": "ComputerCraft",
|
||||||
"tag.item.computercraft.computer": "计算机",
|
"tag.item.computercraft.computer": "计算机",
|
||||||
|
"tag.item.computercraft.disks": "磁盘",
|
||||||
"tag.item.computercraft.dyeable": "可染色物品",
|
"tag.item.computercraft.dyeable": "可染色物品",
|
||||||
"tag.item.computercraft.monitor": "监视器",
|
"tag.item.computercraft.monitor": "监视器",
|
||||||
|
"tag.item.computercraft.pocket_computers": "便携式计算机",
|
||||||
"tag.item.computercraft.turtle": "海龟",
|
"tag.item.computercraft.turtle": "海龟",
|
||||||
"tag.item.computercraft.turtle_can_place": "可放置海龟物品",
|
"tag.item.computercraft.turtle_can_place": "可放置海龟物品",
|
||||||
"tag.item.computercraft.wired_modem": "有线调制解调器",
|
"tag.item.computercraft.wired_modem": "有线调制解调器",
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.gametest
|
||||||
|
|
||||||
|
import dan200.computercraft.core.util.Colour
|
||||||
|
import dan200.computercraft.gametest.api.craftItem
|
||||||
|
import dan200.computercraft.gametest.api.immediate
|
||||||
|
import dan200.computercraft.shared.ModRegistry
|
||||||
|
import dan200.computercraft.shared.util.DataComponentUtil
|
||||||
|
import dan200.computercraft.test.shared.ItemStackMatcher.isStack
|
||||||
|
import net.minecraft.core.component.DataComponents
|
||||||
|
import net.minecraft.gametest.framework.GameTest
|
||||||
|
import net.minecraft.gametest.framework.GameTestHelper
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import net.minecraft.world.item.component.DyedItemColor
|
||||||
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
|
|
||||||
|
class Disk_Test {
|
||||||
|
/**
|
||||||
|
* Ensure disks
|
||||||
|
*/
|
||||||
|
@GameTest(template = "default")
|
||||||
|
fun Can_craft_disk(helper: GameTestHelper) = helper.immediate {
|
||||||
|
assertThat(
|
||||||
|
"Disk without dye",
|
||||||
|
helper.craftItem(ItemStack(Items.REDSTONE), ItemStack(Items.PAPER)),
|
||||||
|
isStack(
|
||||||
|
DataComponentUtil.createStack(
|
||||||
|
ModRegistry.Items.DISK.get(),
|
||||||
|
DataComponents.DYED_COLOR,
|
||||||
|
DyedItemColor(Colour.BLUE.hex, false),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
"Disk with dye",
|
||||||
|
helper.craftItem(ItemStack(Items.REDSTONE), ItemStack(Items.PAPER), ItemStack(Items.GREEN_DYE)),
|
||||||
|
isStack(
|
||||||
|
DataComponentUtil.createStack(
|
||||||
|
ModRegistry.Items.DISK.get(),
|
||||||
|
DataComponents.DYED_COLOR,
|
||||||
|
DyedItemColor(Colour.GREEN.hex, false),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -111,6 +111,7 @@ object TestHooks {
|
|||||||
Computer_Test::class.java,
|
Computer_Test::class.java,
|
||||||
CraftOs_Test::class.java,
|
CraftOs_Test::class.java,
|
||||||
Details_Test::class.java,
|
Details_Test::class.java,
|
||||||
|
Disk_Test::class.java,
|
||||||
Disk_Drive_Test::class.java,
|
Disk_Drive_Test::class.java,
|
||||||
Inventory_Test::class.java,
|
Inventory_Test::class.java,
|
||||||
Loot_Test::class.java,
|
Loot_Test::class.java,
|
||||||
|
@@ -1,3 +1,23 @@
|
|||||||
|
# New features in CC: Tweaked 1.116.0
|
||||||
|
|
||||||
|
* Add `turtle.getEquippedLeft()` and `turtle.getEquippedRight()`.
|
||||||
|
* Add item tags for floppy disks and pocket computers.
|
||||||
|
* Support multi-line strings and comments in `edit`.
|
||||||
|
* Computer and pocket computer terminal sizes can be set with the `computercraft:terminal_size` component.
|
||||||
|
* Border and sidebar textures now use vanilla's nine-sliced format.
|
||||||
|
|
||||||
|
Several bug fixes:
|
||||||
|
* Ignore shader compilation errors when running with Pojav.
|
||||||
|
* Fix several issues with character input.
|
||||||
|
* Fix pocket computer dyes being lost when equipping/unequipping upgrades.
|
||||||
|
* Fix superflous warnings from allocation tracking.
|
||||||
|
* Fix `__lt`/`__le` not working on heterogeneous types.
|
||||||
|
* Many documentation fixes (Lemmmy, matematikaadit, McJack12).
|
||||||
|
* Fix `0` being treated as a valid colour in `window` and `colour.toBlit`.
|
||||||
|
* Fix out-of-bounds when pasting too lon text.
|
||||||
|
* Fix syntax highlighting of string escapes (LorneHyde).
|
||||||
|
* Fix sidebar texture of advanced computers being offset.
|
||||||
|
|
||||||
# New features in CC: Tweaked 1.115.1
|
# New features in CC: Tweaked 1.115.1
|
||||||
|
|
||||||
* Update various translations (cyb3r, kevk2156, teamer337, yakku).
|
* Update various translations (cyb3r, kevk2156, teamer337, yakku).
|
||||||
|
@@ -1,11 +1,21 @@
|
|||||||
New features in CC: Tweaked 1.115.1
|
New features in CC: Tweaked 1.116.0
|
||||||
|
|
||||||
* Update various translations (cyb3r, kevk2156, teamer337, yakku).
|
* Add `turtle.getEquippedLeft()` and `turtle.getEquippedRight()`.
|
||||||
* Support Fabric's item lookup API for registering media providers.
|
* Add item tags for floppy disks and pocket computers.
|
||||||
|
* Support multi-line strings and comments in `edit`.
|
||||||
|
* Computer and pocket computer terminal sizes can be set with the `computercraft:terminal_size` component.
|
||||||
|
* Border and sidebar textures now use vanilla's nine-sliced format.
|
||||||
|
|
||||||
Several bug fixes:
|
Several bug fixes:
|
||||||
* Fix crashes on Create 6.0 (ellellie).
|
* Ignore shader compilation errors when running with Pojav.
|
||||||
* Fix `speaker.playAudio` not updating speaker volume.
|
* Fix several issues with character input.
|
||||||
* Resize pocket lectern textures to fix issues with generating mipmaps.
|
* Fix pocket computer dyes being lost when equipping/unequipping upgrades.
|
||||||
|
* Fix superflous warnings from allocation tracking.
|
||||||
|
* Fix `__lt`/`__le` not working on heterogeneous types.
|
||||||
|
* Many documentation fixes (Lemmmy, matematikaadit, McJack12).
|
||||||
|
* Fix `0` being treated as a valid colour in `window` and `colour.toBlit`.
|
||||||
|
* Fix out-of-bounds when pasting too lon text.
|
||||||
|
* Fix syntax highlighting of string escapes (LorneHyde).
|
||||||
|
* Fix sidebar texture of advanced computers being offset.
|
||||||
|
|
||||||
Type "help changelog" to see the full version history.
|
Type "help changelog" to see the full version history.
|
||||||
|
@@ -0,0 +1,58 @@
|
|||||||
|
-- SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
--
|
||||||
|
-- SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
--[[- Launches a program, reports any errors, and prompts the user to close the
|
||||||
|
tab.
|
||||||
|
|
||||||
|
> [!DANGER]
|
||||||
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
|
> be removed or changed at any time.
|
||||||
|
|
||||||
|
This is used by the `edit` program to launch the running code.
|
||||||
|
|
||||||
|
@tparam string title The title of the multishell tab.
|
||||||
|
@tparam string path The path to the file.
|
||||||
|
@tparam string contents The contents of the file.
|
||||||
|
|
||||||
|
@local
|
||||||
|
]]
|
||||||
|
return function(title, path, contents)
|
||||||
|
multishell.setTitle(multishell.getCurrent(), title)
|
||||||
|
local current = term.current()
|
||||||
|
local fn, err = load(contents, path, nil, _ENV)
|
||||||
|
if fn then
|
||||||
|
local exception = require "cc.internal.exception"
|
||||||
|
local ok, err, co = exception.try(fn)
|
||||||
|
|
||||||
|
term.redirect(current)
|
||||||
|
term.setTextColor(term.isColour() and colours.yellow or colours.white)
|
||||||
|
term.setBackgroundColor(colours.black)
|
||||||
|
term.setCursorBlink(false)
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
printError(err)
|
||||||
|
exception.report(err, co, { [path] = contents })
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local parser = require "cc.internal.syntax"
|
||||||
|
if parser.parse_program(contents) then printError(err) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local message = "Press any key to continue."
|
||||||
|
local _, y = term.getCursorPos()
|
||||||
|
local w, h = term.getSize()
|
||||||
|
local wrapped = require("cc.strings").wrap(message, w)
|
||||||
|
|
||||||
|
term.setTextColor(colours.white)
|
||||||
|
term.setBackgroundColor(colours.black)
|
||||||
|
|
||||||
|
local start_y = h - #wrapped + 1
|
||||||
|
if y >= start_y then term.scroll(y - start_y + 1) end
|
||||||
|
for i = 1, #wrapped do
|
||||||
|
term.setCursorPos(1, start_y + i - 1)
|
||||||
|
term.write(wrapped[i])
|
||||||
|
end
|
||||||
|
os.pullEvent('key')
|
||||||
|
require "cc.internal.event".discard_char()
|
||||||
|
end
|
@@ -0,0 +1,125 @@
|
|||||||
|
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
|
||||||
|
--
|
||||||
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
|
--[[- A simple menu bar.
|
||||||
|
|
||||||
|
> [!DANGER]
|
||||||
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
|
> be removed or changed at any time.
|
||||||
|
|
||||||
|
This provides a shared implementation of the menu bar used by the `edit` and
|
||||||
|
`paint` programs. This draws a menu bar at the bottom of the string, with a list
|
||||||
|
of options.
|
||||||
|
|
||||||
|
@local
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expect = require "cc.expect".expect
|
||||||
|
|
||||||
|
--[[- Create a new menu bar.
|
||||||
|
|
||||||
|
This should be called every time the menu is displayed.
|
||||||
|
|
||||||
|
@tparam { string... } items The menu items to display.
|
||||||
|
@return The menu.
|
||||||
|
]]
|
||||||
|
local function create(items)
|
||||||
|
expect(1, items, "table")
|
||||||
|
return {
|
||||||
|
items = items,
|
||||||
|
selected = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[- Draw the menu bar at the bottom of the screen.
|
||||||
|
|
||||||
|
This should be called when first displaying the menu, and if the whole screen is
|
||||||
|
redrawn (e.g. after a [`term_resize`]).
|
||||||
|
|
||||||
|
@param menu The menu bar to draw.
|
||||||
|
]]
|
||||||
|
local function draw(menu)
|
||||||
|
expect(1, menu, "table")
|
||||||
|
|
||||||
|
local _, height = term.getSize()
|
||||||
|
term.setCursorPos(1, height)
|
||||||
|
|
||||||
|
term.clearLine()
|
||||||
|
|
||||||
|
local active_colour = term.isColour() and colours.yellow or colours.white
|
||||||
|
term.setTextColour(colours.white)
|
||||||
|
for k, v in pairs(menu.items) do
|
||||||
|
if menu.selected == k then
|
||||||
|
term.setTextColour(active_colour)
|
||||||
|
term.write("[")
|
||||||
|
term.setTextColour(colours.white)
|
||||||
|
term.write(v)
|
||||||
|
term.setTextColour(active_colour)
|
||||||
|
term.write("]")
|
||||||
|
term.setTextColour(colours.white)
|
||||||
|
else
|
||||||
|
term.write(" " .. v .. " ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[- Process an event.
|
||||||
|
|
||||||
|
@param menu The menu bar to update.
|
||||||
|
@tparam string The event name.
|
||||||
|
@param ... Additional arguments to the event.
|
||||||
|
@treturn nil|boolean|string Either:
|
||||||
|
|
||||||
|
- If no action was taken, return `nil`.
|
||||||
|
- If the menu was closed, return `false`.
|
||||||
|
- If an item was selected, return the item as a string.
|
||||||
|
]]
|
||||||
|
local function handle_event(menu, event, ...)
|
||||||
|
expect(1, menu, "table")
|
||||||
|
|
||||||
|
if event == "key" then
|
||||||
|
local key = ...
|
||||||
|
|
||||||
|
if key == keys.right then
|
||||||
|
-- Move right
|
||||||
|
menu.selected = menu.selected + 1
|
||||||
|
if menu.selected > #menu.items then menu.selected = 1 end
|
||||||
|
draw(menu)
|
||||||
|
elseif key == keys.left and menu.selected > 1 then
|
||||||
|
-- Move left
|
||||||
|
menu.selected = menu.selected - 1
|
||||||
|
if menu.selected < 1 then menu.selected = #menu.items end
|
||||||
|
draw(menu)
|
||||||
|
elseif key == keys.enter or key == keys.numPadEnter then
|
||||||
|
-- Select an option
|
||||||
|
return menu.items[menu.selected]
|
||||||
|
elseif key == keys.leftCtrl or keys == keys.rightCtrl or keys == keys.rightAlt then
|
||||||
|
-- Cancel the menu
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
elseif event == "char" then
|
||||||
|
-- Select menu items
|
||||||
|
local char = (...):lower()
|
||||||
|
for _, item in pairs(menu.items) do
|
||||||
|
if item:sub(1, 1):lower() == char then return item end
|
||||||
|
end
|
||||||
|
elseif event == "mouse_click" then
|
||||||
|
local _, x, y = ...
|
||||||
|
|
||||||
|
local _, height = term.getSize()
|
||||||
|
if y ~= height then return false end -- Exit the menu
|
||||||
|
|
||||||
|
local item_start = 1
|
||||||
|
for _, item in ipairs(menu.items) do
|
||||||
|
local item_end = item_start + #item + 2
|
||||||
|
if x >= item_start and x < item_end then return item end
|
||||||
|
item_start = item_end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return { create = create, draw = draw, handle_event = handle_event }
|
@@ -101,16 +101,21 @@ local function lex_number(context, str, start)
|
|||||||
return tokens.NUMBER, pos - 1
|
return tokens.NUMBER, pos - 1
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Lex a quoted string.
|
local lex_string_zap
|
||||||
--
|
|
||||||
-- @param context The current parser context.
|
--[[- Lex a quoted string.
|
||||||
-- @tparam string str The string we're lexing.
|
|
||||||
-- @tparam number start_pos The start position of the string.
|
@param context The current parser context.
|
||||||
-- @tparam string quote The quote character, either " or '.
|
@tparam string str The string we're lexing.
|
||||||
-- @treturn number The token id for strings.
|
@tparam number pos The position to start lexing from.
|
||||||
-- @treturn number The new position.
|
@tparam number start_pos The actual start position of the string.
|
||||||
local function lex_string(context, str, start_pos, quote)
|
@tparam string quote The quote character, either " or '.
|
||||||
local pos = start_pos + 1
|
@treturn number The token id for strings.
|
||||||
|
@treturn number The new position.
|
||||||
|
@treturn nil A placeholder value.
|
||||||
|
@treturn table|nil The continuation function when the string is not finished.
|
||||||
|
]]
|
||||||
|
local function lex_string(context, str, pos, start_pos, quote)
|
||||||
while true do
|
while true do
|
||||||
local c = sub(str, pos, pos)
|
local c = sub(str, pos, pos)
|
||||||
if c == quote then
|
if c == quote then
|
||||||
@@ -125,15 +130,38 @@ local function lex_string(context, str, start_pos, quote)
|
|||||||
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, nil, { lex_string, 1, 1, quote }
|
||||||
elseif c == "z" then
|
elseif c == "z" then
|
||||||
|
return lex_string_zap(context, str, pos + 2, start_pos, quote)
|
||||||
|
else
|
||||||
pos = pos + 2
|
pos = pos + 2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
pos = pos + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[- Lex the remainder of a zap escape sequence (`\z`). This consumes all leading
|
||||||
|
whitespace, and then continues lexing the string.
|
||||||
|
|
||||||
|
@param context The current parser context.
|
||||||
|
@tparam string str The string we're lexing.
|
||||||
|
@tparam number pos The position to start lexing from.
|
||||||
|
@tparam number start_pos The actual start position of the string.
|
||||||
|
@tparam string quote The quote character, either " or '.
|
||||||
|
@treturn number The token id for strings.
|
||||||
|
@treturn number The new position.
|
||||||
|
@treturn nil A placeholder value.
|
||||||
|
@treturn table|nil The continuation function when the string is not finished.
|
||||||
|
]]
|
||||||
|
lex_string_zap = function(context, str, pos, start_pos, quote)
|
||||||
while true do
|
while true do
|
||||||
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, nil, { lex_string_zap, 1, 1, quote }
|
||||||
end
|
end
|
||||||
|
|
||||||
if c == "\n" or c == "\r" then
|
if c == "\n" or c == "\r" then
|
||||||
@@ -143,13 +171,8 @@ local function lex_string(context, str, start_pos, quote)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
pos = pos + 2
|
return lex_string(context, str, pos, start_pos, quote)
|
||||||
end
|
|
||||||
else
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Consume the start or end of a long string.
|
--- Consume the start or end of a long string.
|
||||||
@@ -205,6 +228,45 @@ local function lex_long_str(context, str, start, len)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[- Lex the remainder of a long string.
|
||||||
|
|
||||||
|
@param context The current parser context.
|
||||||
|
@tparam string str The string we're lexing.
|
||||||
|
@tparam number pos The position to start lexing from.
|
||||||
|
@tparam number start_pos The actual start position of the string.
|
||||||
|
@tparam number boundary_length The length of the boundary.
|
||||||
|
@treturn number The token id for strings.
|
||||||
|
@treturn number The new position.
|
||||||
|
@treturn nil A placeholder value.
|
||||||
|
@treturn table|nil The continuation function when the string is not finished.
|
||||||
|
]]
|
||||||
|
local function lex_long_string(context, str, pos, start_pos, boundary_length)
|
||||||
|
local end_pos = lex_long_str(context, str, pos, boundary_length)
|
||||||
|
if end_pos then return tokens.STRING, end_pos end
|
||||||
|
|
||||||
|
context.report(errors.unfinished_long_string, start_pos, pos - 1, boundary_length)
|
||||||
|
return tokens.STRING, #str, nil, { lex_long_string, 0, 0, boundary_length }
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[- Lex the remainder of a long comment.
|
||||||
|
|
||||||
|
@param context The current parser context.
|
||||||
|
@tparam string str The comment we're lexing.
|
||||||
|
@tparam number pos The position to start lexing from.
|
||||||
|
@tparam number start_pos The actual start position of the comment.
|
||||||
|
@tparam number boundary_length The length of the boundary.
|
||||||
|
@treturn number The token id for comments.
|
||||||
|
@treturn number The new position.
|
||||||
|
@treturn nil A placeholder value.
|
||||||
|
@treturn table|nil The continuation function when the comment is not finished.
|
||||||
|
]]
|
||||||
|
local function lex_long_comment(context, str, pos, start_pos, boundary_length)
|
||||||
|
local end_pos = lex_long_str(context, str, pos, boundary_length)
|
||||||
|
if end_pos then return tokens.COMMENT, end_pos end
|
||||||
|
|
||||||
|
context.report(errors.unfinished_long_comment, start_pos, pos - 1, boundary_length)
|
||||||
|
return tokens.COMMENT, #str, nil, { lex_long_comment, 0, 0, boundary_length }
|
||||||
|
end
|
||||||
|
|
||||||
--- Lex a single token, assuming we have removed all leading whitespace.
|
--- Lex a single token, assuming we have removed all leading whitespace.
|
||||||
--
|
--
|
||||||
@@ -229,16 +291,12 @@ local function lex_token(context, str, pos)
|
|||||||
elseif c >= "0" and c <= "9" then return lex_number(context, str, pos)
|
elseif c >= "0" and c <= "9" then return lex_number(context, str, pos)
|
||||||
|
|
||||||
-- Strings
|
-- Strings
|
||||||
elseif c == "\"" or c == "\'" then return lex_string(context, str, pos, c)
|
elseif c == "\"" or c == "\'" then return lex_string(context, str, pos + 1, pos, c)
|
||||||
|
|
||||||
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 then -- Long string
|
if ok then -- Long string
|
||||||
local end_pos = lex_long_str(context, str, boundary_pos + 1, boundary_pos - pos)
|
return lex_long_string(context, str, boundary_pos + 1, pos, boundary_pos - pos)
|
||||||
if end_pos then return tokens.STRING, end_pos end
|
|
||||||
|
|
||||||
context.report(errors.unfinished_long_string, pos, boundary_pos, boundary_pos - pos)
|
|
||||||
return tokens.STRING, #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 "[="
|
||||||
@@ -256,11 +314,7 @@ local function lex_token(context, str, pos)
|
|||||||
if sub(str, comment_pos, comment_pos) == "[" then
|
if sub(str, comment_pos, comment_pos) == "[" then
|
||||||
local ok, boundary_pos = lex_long_str_boundary(str, comment_pos + 1, "[")
|
local ok, boundary_pos = lex_long_str_boundary(str, comment_pos + 1, "[")
|
||||||
if ok then
|
if ok then
|
||||||
local end_pos = lex_long_str(context, str, boundary_pos + 1, boundary_pos - comment_pos)
|
return lex_long_comment(context, str, boundary_pos + 1, pos, boundary_pos - comment_pos)
|
||||||
if end_pos then return tokens.COMMENT, end_pos end
|
|
||||||
|
|
||||||
context.report(errors.unfinished_long_comment, pos, boundary_pos, boundary_pos - comment_pos)
|
|
||||||
return tokens.COMMENT, #str
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -357,8 +411,8 @@ local function lex_one(context, str, pos)
|
|||||||
elseif c == "\r" or c == "\n" then
|
elseif c == "\r" or c == "\n" then
|
||||||
pos = newline(context, str, start_pos, c)
|
pos = newline(context, str, start_pos, c)
|
||||||
else
|
else
|
||||||
local token_id, end_pos, content = lex_token(context, str, start_pos)
|
local token_id, end_pos, content, continue = lex_token(context, str, start_pos)
|
||||||
return token_id, start_pos, end_pos, content
|
return token_id, start_pos, end_pos, content, continue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -30,81 +30,40 @@ local x, y = 1, 1
|
|||||||
local w, h = term.getSize()
|
local w, h = term.getSize()
|
||||||
local scrollX, scrollY = 0, 0
|
local scrollX, scrollY = 0, 0
|
||||||
|
|
||||||
local tLines = {}
|
local tLines, tLineLexStates = {}, {}
|
||||||
local bRunning = true
|
local bRunning = true
|
||||||
|
|
||||||
-- Colours
|
-- Colours
|
||||||
local highlightColour, keywordColour, commentColour, textColour, bgColour, stringColour, errorColour
|
local isColour = term.isColour()
|
||||||
if term.isColour() then
|
local highlightColour, keywordColour, textColour, bgColour, errorColour
|
||||||
|
if isColour then
|
||||||
bgColour = colours.black
|
bgColour = colours.black
|
||||||
textColour = colours.white
|
textColour = colours.white
|
||||||
highlightColour = colours.yellow
|
highlightColour = colours.yellow
|
||||||
keywordColour = colours.yellow
|
keywordColour = colours.yellow
|
||||||
commentColour = colours.green
|
|
||||||
stringColour = colours.red
|
|
||||||
errorColour = colours.red
|
errorColour = colours.red
|
||||||
else
|
else
|
||||||
bgColour = colours.black
|
bgColour = colours.black
|
||||||
textColour = colours.white
|
textColour = colours.white
|
||||||
highlightColour = colours.white
|
highlightColour = colours.white
|
||||||
keywordColour = colours.white
|
keywordColour = colours.white
|
||||||
commentColour = colours.white
|
|
||||||
stringColour = colours.white
|
|
||||||
errorColour = colours.white
|
errorColour = colours.white
|
||||||
end
|
end
|
||||||
|
|
||||||
local runHandler = [[multishell.setTitle(multishell.getCurrent(), %q)
|
|
||||||
local current = term.current()
|
|
||||||
local contents, name = %q, %q
|
|
||||||
local fn, err = load(contents, name, nil, _ENV)
|
|
||||||
if fn then
|
|
||||||
local exception = require "cc.internal.exception"
|
|
||||||
local ok, err, co = exception.try(fn, ...)
|
|
||||||
|
|
||||||
term.redirect(current)
|
|
||||||
term.setTextColor(term.isColour() and colours.yellow or colours.white)
|
|
||||||
term.setBackgroundColor(colours.black)
|
|
||||||
term.setCursorBlink(false)
|
|
||||||
|
|
||||||
if not ok then
|
|
||||||
printError(err)
|
|
||||||
exception.report(err, co, { [name] = contents })
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local parser = require "cc.internal.syntax"
|
|
||||||
if parser.parse_program(contents) then printError(err) end
|
|
||||||
end
|
|
||||||
|
|
||||||
local message = "Press any key to continue."
|
|
||||||
if ok then message = "Program finished. " .. message end
|
|
||||||
local _, y = term.getCursorPos()
|
|
||||||
local w, h = term.getSize()
|
|
||||||
local wrapped = require("cc.strings").wrap(message, w)
|
|
||||||
|
|
||||||
local start_y = h - #wrapped + 1
|
|
||||||
if y >= start_y then term.scroll(y - start_y + 1) end
|
|
||||||
for i = 1, #wrapped do
|
|
||||||
term.setCursorPos(1, start_y + i - 1)
|
|
||||||
term.write(wrapped[i])
|
|
||||||
end
|
|
||||||
os.pullEvent('key')
|
|
||||||
require "cc.internal.event".discard_char()
|
|
||||||
]]
|
|
||||||
|
|
||||||
-- Menus
|
-- Menus
|
||||||
local bMenu = false
|
local menu = require "cc.internal.menu"
|
||||||
local nMenuItem = 1
|
local current_menu
|
||||||
local tMenuItems = {}
|
local menu_items = {}
|
||||||
if not bReadOnly then
|
if not bReadOnly then
|
||||||
table.insert(tMenuItems, "Save")
|
table.insert(menu_items, "Save")
|
||||||
end
|
end
|
||||||
if shell.openTab then
|
if shell.openTab then
|
||||||
table.insert(tMenuItems, "Run")
|
table.insert(menu_items, "Run")
|
||||||
end
|
end
|
||||||
if peripheral.find("printer") then
|
if peripheral.find("printer") then
|
||||||
table.insert(tMenuItems, "Print")
|
table.insert(menu_items, "Print")
|
||||||
end
|
end
|
||||||
table.insert(tMenuItems, "Exit")
|
table.insert(menu_items, "Exit")
|
||||||
|
|
||||||
local status_ok, status_text
|
local status_ok, status_text
|
||||||
local function set_status(text, ok)
|
local function set_status(text, ok)
|
||||||
@@ -138,6 +97,7 @@ local function load(_sPath)
|
|||||||
local sLine = file:read()
|
local sLine = file:read()
|
||||||
while sLine do
|
while sLine do
|
||||||
table.insert(tLines, sLine)
|
table.insert(tLines, sLine)
|
||||||
|
table.insert(tLineLexStates, false)
|
||||||
sLine = file:read()
|
sLine = file:read()
|
||||||
end
|
end
|
||||||
file:close()
|
file:close()
|
||||||
@@ -145,6 +105,7 @@ local function load(_sPath)
|
|||||||
|
|
||||||
if #tLines == 0 then
|
if #tLines == 0 then
|
||||||
table.insert(tLines, "")
|
table.insert(tLines, "")
|
||||||
|
table.insert(tLineLexStates, false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -180,8 +141,9 @@ local tokens = require "cc.internal.syntax.parser".tokens
|
|||||||
local lex_one = require "cc.internal.syntax.lexer".lex_one
|
local lex_one = require "cc.internal.syntax.lexer".lex_one
|
||||||
|
|
||||||
local token_colours = {
|
local token_colours = {
|
||||||
[tokens.STRING] = stringColour,
|
[tokens.STRING] = isColour and colours.red or textColour,
|
||||||
[tokens.COMMENT] = commentColour,
|
[tokens.COMMENT] = isColour and colours.green or colours.lightGrey,
|
||||||
|
[tokens.NUMBER] = isColour and colours.magenta or textColour,
|
||||||
-- Keywords
|
-- Keywords
|
||||||
[tokens.AND] = keywordColour,
|
[tokens.AND] = keywordColour,
|
||||||
[tokens.BREAK] = keywordColour,
|
[tokens.BREAK] = keywordColour,
|
||||||
@@ -213,26 +175,6 @@ end
|
|||||||
|
|
||||||
local lex_context = { line = function() end, report = function() end }
|
local lex_context = { line = function() end, report = function() end }
|
||||||
|
|
||||||
local function writeHighlighted(line)
|
|
||||||
local pos, colour = 1, nil
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local token, _, finish = lex_one(lex_context, line, pos)
|
|
||||||
if not token then break end
|
|
||||||
|
|
||||||
local new_colour = token_colours[token]
|
|
||||||
if new_colour ~= colour then
|
|
||||||
term.setTextColor(new_colour)
|
|
||||||
colour = new_colour
|
|
||||||
end
|
|
||||||
|
|
||||||
term.write(line:sub(pos, finish))
|
|
||||||
pos = finish + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
term.write(line:sub(pos))
|
|
||||||
end
|
|
||||||
|
|
||||||
local tCompletions
|
local tCompletions
|
||||||
local nCompletion
|
local nCompletion
|
||||||
|
|
||||||
@@ -252,7 +194,7 @@ end
|
|||||||
|
|
||||||
local function recomplete()
|
local function recomplete()
|
||||||
local sLine = tLines[y]
|
local sLine = tLines[y]
|
||||||
if not bMenu and not bReadOnly and x == #sLine + 1 then
|
if not bReadOnly and x == #sLine + 1 then
|
||||||
tCompletions = complete(sLine)
|
tCompletions = complete(sLine)
|
||||||
if tCompletions and #tCompletions > 0 then
|
if tCompletions and #tCompletions > 0 then
|
||||||
nCompletion = 1
|
nCompletion = 1
|
||||||
@@ -276,34 +218,94 @@ local function writeCompletion(sLine)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function redrawText()
|
--- Check if two values are equal. If both values are lists, then the contents will be
|
||||||
local cursorX, cursorY = x, y
|
-- checked for equality, to a depth of 1.
|
||||||
for y = 1, h - 1 do
|
--
|
||||||
term.setCursorPos(1 - scrollX, y)
|
-- @param x The first value.
|
||||||
|
-- @param x The second value.
|
||||||
|
-- @treturn boolean Whether the values are equal.
|
||||||
|
local function shallowEqual(x, y)
|
||||||
|
if x == y then return true end
|
||||||
|
|
||||||
|
if type(x) ~= "table" or type(y) ~= "table" then return false end
|
||||||
|
if #x ~= #y then return false end
|
||||||
|
|
||||||
|
for i = 1, #x do if x[i] ~= y[i] then return false end end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function redrawLines(line, endLine)
|
||||||
|
if not endLine then endLine = line end
|
||||||
|
|
||||||
|
local colour = term.getTextColour()
|
||||||
|
|
||||||
|
-- Highlight all lines between line and endLine, highlighting further lines if their
|
||||||
|
-- lexer state has changed and aborting at the end of the screen.
|
||||||
|
local changed = false
|
||||||
|
while (changed or line <= endLine) and line - scrollY < h do
|
||||||
|
term.setCursorPos(1 - scrollX, line - scrollY)
|
||||||
term.clearLine()
|
term.clearLine()
|
||||||
|
|
||||||
local sLine = tLines[y + scrollY]
|
local contents = tLines[line]
|
||||||
if sLine ~= nil then
|
if not contents then break end
|
||||||
writeHighlighted(sLine)
|
|
||||||
if cursorY == y and cursorX == #sLine + 1 then
|
-- Lex our first token, either taking our continuation state (if present) or
|
||||||
|
-- the default lexer.
|
||||||
|
local pos, token, _, finish, continuation = 1
|
||||||
|
local lex_state = tLineLexStates[line]
|
||||||
|
if lex_state then
|
||||||
|
token, finish, _, continuation = lex_state[1](lex_context, contents, table.unpack(lex_state, 2))
|
||||||
|
else
|
||||||
|
token, _, finish, _, continuation = lex_one(lex_context, contents, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
while token do
|
||||||
|
-- Print out that token
|
||||||
|
local new_colour = token_colours[token]
|
||||||
|
if new_colour ~= colour then
|
||||||
|
term.setTextColor(new_colour)
|
||||||
|
colour = new_colour
|
||||||
|
end
|
||||||
|
term.write(contents:sub(pos, finish))
|
||||||
|
|
||||||
|
pos = finish + 1
|
||||||
|
|
||||||
|
-- If we have a continuation, then we've reached the end of the line. Abort.
|
||||||
|
if continuation then break end
|
||||||
|
|
||||||
|
-- Otherwise lex another token and continue.
|
||||||
|
token, _, finish, _, continuation = lex_one(lex_context, contents, pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Print the rest of the line. We don't strictly speaking need this, as it will
|
||||||
|
-- only ever contain whitespace.
|
||||||
|
term.write(contents:sub(pos))
|
||||||
|
|
||||||
|
if line == y and x == #contents + 1 then
|
||||||
writeCompletion()
|
writeCompletion()
|
||||||
|
colour = term.getTextColour()
|
||||||
|
end
|
||||||
|
|
||||||
|
line = line + 1
|
||||||
|
|
||||||
|
-- Update the lext state of the next line. If that has changed, then
|
||||||
|
-- re-highlight it too. We store the continuation as nil rather than
|
||||||
|
-- false, to ensure we use the array part of the table.
|
||||||
|
if continuation == nil then continuation = false end
|
||||||
|
if tLineLexStates[line] ~= nil and not shallowEqual(tLineLexStates[line], continuation) then
|
||||||
|
tLineLexStates[line] = continuation or false
|
||||||
|
changed = true
|
||||||
|
else
|
||||||
|
changed = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
term.setTextColor(colours.white)
|
||||||
term.setCursorPos(x - scrollX, y - scrollY)
|
term.setCursorPos(x - scrollX, y - scrollY)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function redrawLine(_nY)
|
local function redrawText()
|
||||||
local sLine = tLines[_nY]
|
redrawLines(scrollY + 1, scrollY + h - 1)
|
||||||
if sLine then
|
|
||||||
term.setCursorPos(1 - scrollX, _nY - scrollY)
|
|
||||||
term.clearLine()
|
|
||||||
writeHighlighted(sLine)
|
|
||||||
if _nY == y and x == #sLine + 1 then
|
|
||||||
writeCompletion()
|
|
||||||
end
|
|
||||||
term.setCursorPos(x - scrollX, _nY - scrollY)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function redrawMenu()
|
local function redrawMenu()
|
||||||
@@ -319,22 +321,9 @@ local function redrawMenu()
|
|||||||
term.write(y)
|
term.write(y)
|
||||||
|
|
||||||
term.setCursorPos(1, h)
|
term.setCursorPos(1, h)
|
||||||
if bMenu then
|
if current_menu then
|
||||||
-- Draw menu
|
-- Draw menu
|
||||||
term.setTextColour(textColour)
|
menu.draw(current_menu)
|
||||||
for nItem, sItem in pairs(tMenuItems) do
|
|
||||||
if nItem == nMenuItem then
|
|
||||||
term.setTextColour(highlightColour)
|
|
||||||
term.write("[")
|
|
||||||
term.setTextColour(textColour)
|
|
||||||
term.write(sItem)
|
|
||||||
term.setTextColour(highlightColour)
|
|
||||||
term.write("]")
|
|
||||||
term.setTextColour(textColour)
|
|
||||||
else
|
|
||||||
term.write(" " .. sItem .. " ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
-- Draw status
|
-- Draw status
|
||||||
term.setTextColour(status_ok and highlightColour or errorColour)
|
term.setTextColour(status_ok and highlightColour or errorColour)
|
||||||
@@ -344,6 +333,7 @@ local function redrawMenu()
|
|||||||
|
|
||||||
-- Reset cursor
|
-- Reset cursor
|
||||||
term.setCursorPos(x - scrollX, y - scrollY)
|
term.setCursorPos(x - scrollX, y - scrollY)
|
||||||
|
term.setCursorBlink(not current_menu)
|
||||||
end
|
end
|
||||||
|
|
||||||
local tMenuFuncs = {
|
local tMenuFuncs = {
|
||||||
@@ -421,7 +411,8 @@ local tMenuFuncs = {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
bMenu = false
|
local old_menu = current_menu
|
||||||
|
current_menu = nil
|
||||||
term.redirect(printerTerminal)
|
term.redirect(printerTerminal)
|
||||||
local ok, error = pcall(function()
|
local ok, error = pcall(function()
|
||||||
term.scroll()
|
term.scroll()
|
||||||
@@ -439,7 +430,7 @@ local tMenuFuncs = {
|
|||||||
redrawMenu()
|
redrawMenu()
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
end
|
end
|
||||||
bMenu = true
|
current_menu = old_menu
|
||||||
|
|
||||||
if nPage > 1 then
|
if nPage > 1 then
|
||||||
set_status("Printed " .. nPage .. " Pages")
|
set_status("Printed " .. nPage .. " Pages")
|
||||||
@@ -462,7 +453,8 @@ local tMenuFuncs = {
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
local ok = save(sTempPath, function(file)
|
local ok = save(sTempPath, function(file)
|
||||||
file.write(runHandler:format(sTitle, table.concat(tLines, "\n"), "@/" .. sPath))
|
local runHandler = [[return require("cc.internal.edit_runner")(%q, %q, %q)]]
|
||||||
|
file.write(runHandler:format(sTitle, "@/" .. sPath, table.concat(tLines, "\n")))
|
||||||
end)
|
end)
|
||||||
if ok then
|
if ok then
|
||||||
local nTask = shell.openTab("/" .. sTempPath)
|
local nTask = shell.openTab("/" .. sTempPath)
|
||||||
@@ -479,15 +471,6 @@ local tMenuFuncs = {
|
|||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
local function doMenuItem(_n)
|
|
||||||
tMenuFuncs[tMenuItems[_n]]()
|
|
||||||
if bMenu then
|
|
||||||
bMenu = false
|
|
||||||
term.setCursorBlink(true)
|
|
||||||
end
|
|
||||||
redrawMenu()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setCursor(newX, newY)
|
local function setCursor(newX, newY)
|
||||||
local _, oldY = x, y
|
local _, oldY = x, y
|
||||||
x, y = newX, newY
|
x, y = newX, newY
|
||||||
@@ -519,12 +502,10 @@ local function setCursor(newX, newY)
|
|||||||
if bRedraw then
|
if bRedraw then
|
||||||
redrawText()
|
redrawText()
|
||||||
elseif y ~= oldY then
|
elseif y ~= oldY then
|
||||||
redrawLine(oldY)
|
redrawLines(math.min(y, oldY), math.max(y, oldY))
|
||||||
redrawLine(y)
|
|
||||||
else
|
else
|
||||||
redrawLine(y)
|
redrawLines(y)
|
||||||
end
|
end
|
||||||
term.setCursorPos(screenX, screenY)
|
|
||||||
|
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
end
|
end
|
||||||
@@ -550,20 +531,36 @@ local function acceptCompletion()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function handleMenuEvent(event)
|
||||||
|
assert(current_menu)
|
||||||
|
|
||||||
|
local result = menu.handle_event(current_menu, table.unpack(event, 1, event.n))
|
||||||
|
if result == false then
|
||||||
|
current_menu = nil
|
||||||
|
redrawMenu()
|
||||||
|
elseif result ~= nil then
|
||||||
|
tMenuFuncs[result]()
|
||||||
|
current_menu = nil
|
||||||
|
redrawMenu()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Handle input
|
-- Handle input
|
||||||
while bRunning do
|
while bRunning do
|
||||||
local sEvent, param, param2, param3 = os.pullEvent()
|
local event = table.pack(os.pullEvent())
|
||||||
if sEvent == "key" then
|
if event[1] == "key" then
|
||||||
if param == keys.up then
|
if current_menu then
|
||||||
-- Up
|
handleMenuEvent(event)
|
||||||
if not bMenu then
|
else
|
||||||
|
local key = event[2]
|
||||||
|
if key == keys.up then
|
||||||
if nCompletion then
|
if nCompletion then
|
||||||
-- Cycle completions
|
-- Cycle completions
|
||||||
nCompletion = nCompletion - 1
|
nCompletion = nCompletion - 1
|
||||||
if nCompletion < 1 then
|
if nCompletion < 1 then
|
||||||
nCompletion = #tCompletions
|
nCompletion = #tCompletions
|
||||||
end
|
end
|
||||||
redrawLine(y)
|
redrawLines(y)
|
||||||
|
|
||||||
elseif y > 1 then
|
elseif y > 1 then
|
||||||
-- Move cursor up
|
-- Move cursor up
|
||||||
@@ -572,19 +569,15 @@ while bRunning do
|
|||||||
y - 1
|
y - 1
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.down then
|
elseif key == keys.down then
|
||||||
-- Down
|
|
||||||
if not bMenu then
|
|
||||||
-- Move cursor down
|
|
||||||
if nCompletion then
|
if nCompletion then
|
||||||
-- Cycle completions
|
-- Cycle completions
|
||||||
nCompletion = nCompletion + 1
|
nCompletion = nCompletion + 1
|
||||||
if nCompletion > #tCompletions then
|
if nCompletion > #tCompletions then
|
||||||
nCompletion = 1
|
nCompletion = 1
|
||||||
end
|
end
|
||||||
redrawLine(y)
|
redrawLines(y)
|
||||||
|
|
||||||
elseif y < #tLines then
|
elseif y < #tLines then
|
||||||
-- Move cursor down
|
-- Move cursor down
|
||||||
@@ -593,11 +586,8 @@ while bRunning do
|
|||||||
y + 1
|
y + 1
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.tab then
|
elseif key == keys.tab and not bReadOnly then
|
||||||
-- Tab
|
|
||||||
if not bMenu and not bReadOnly then
|
|
||||||
if nCompletion and x == #tLines[y] + 1 then
|
if nCompletion and x == #tLines[y] + 1 then
|
||||||
-- Accept autocomplete
|
-- Accept autocomplete
|
||||||
acceptCompletion()
|
acceptCompletion()
|
||||||
@@ -607,11 +597,8 @@ while bRunning do
|
|||||||
tLines[y] = string.sub(sLine, 1, x - 1) .. " " .. string.sub(sLine, x)
|
tLines[y] = string.sub(sLine, 1, x - 1) .. " " .. string.sub(sLine, x)
|
||||||
setCursor(x + 4, y)
|
setCursor(x + 4, y)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.pageUp then
|
elseif key == keys.pageUp then
|
||||||
-- Page Up
|
|
||||||
if not bMenu then
|
|
||||||
-- Move up a page
|
-- Move up a page
|
||||||
local newY
|
local newY
|
||||||
if y - (h - 1) >= 1 then
|
if y - (h - 1) >= 1 then
|
||||||
@@ -623,11 +610,7 @@ while bRunning do
|
|||||||
math.min(x, #tLines[newY] + 1),
|
math.min(x, #tLines[newY] + 1),
|
||||||
newY
|
newY
|
||||||
)
|
)
|
||||||
end
|
elseif key == keys.pageDown then
|
||||||
|
|
||||||
elseif param == keys.pageDown then
|
|
||||||
-- Page Down
|
|
||||||
if not bMenu then
|
|
||||||
-- Move down a page
|
-- Move down a page
|
||||||
local newY
|
local newY
|
||||||
if y + (h - 1) <= #tLines then
|
if y + (h - 1) <= #tLines then
|
||||||
@@ -637,48 +620,29 @@ while bRunning do
|
|||||||
end
|
end
|
||||||
local newX = math.min(x, #tLines[newY] + 1)
|
local newX = math.min(x, #tLines[newY] + 1)
|
||||||
setCursor(newX, newY)
|
setCursor(newX, newY)
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.home then
|
elseif key == keys.home then
|
||||||
-- Home
|
|
||||||
if not bMenu then
|
|
||||||
-- Move cursor to the beginning
|
-- Move cursor to the beginning
|
||||||
if x > 1 then
|
if x > 1 then
|
||||||
setCursor(1, y)
|
setCursor(1, y)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys["end"] then
|
elseif key == keys["end"] then
|
||||||
-- End
|
|
||||||
if not bMenu then
|
|
||||||
-- Move cursor to the end
|
-- Move cursor to the end
|
||||||
local nLimit = #tLines[y] + 1
|
local nLimit = #tLines[y] + 1
|
||||||
if x < nLimit then
|
if x < nLimit then
|
||||||
setCursor(nLimit, y)
|
setCursor(nLimit, y)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.left then
|
elseif key == keys.left then
|
||||||
-- Left
|
|
||||||
if not bMenu then
|
|
||||||
if x > 1 then
|
if x > 1 then
|
||||||
-- Move cursor left
|
-- Move cursor left
|
||||||
setCursor(x - 1, y)
|
setCursor(x - 1, y)
|
||||||
elseif x == 1 and y > 1 then
|
elseif x == 1 and y > 1 then
|
||||||
setCursor(#tLines[y - 1] + 1, y - 1)
|
setCursor(#tLines[y - 1] + 1, y - 1)
|
||||||
end
|
end
|
||||||
else
|
|
||||||
-- Move menu left
|
|
||||||
nMenuItem = nMenuItem - 1
|
|
||||||
if nMenuItem < 1 then
|
|
||||||
nMenuItem = #tMenuItems
|
|
||||||
end
|
|
||||||
redrawMenu()
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.right then
|
elseif key == keys.right then
|
||||||
-- Right
|
|
||||||
if not bMenu then
|
|
||||||
local nLimit = #tLines[y] + 1
|
local nLimit = #tLines[y] + 1
|
||||||
if x < nLimit then
|
if x < nLimit then
|
||||||
-- Move cursor right
|
-- Move cursor right
|
||||||
@@ -690,35 +654,23 @@ while bRunning do
|
|||||||
-- Go to next line
|
-- Go to next line
|
||||||
setCursor(1, y + 1)
|
setCursor(1, y + 1)
|
||||||
end
|
end
|
||||||
else
|
|
||||||
-- Move menu right
|
|
||||||
nMenuItem = nMenuItem + 1
|
|
||||||
if nMenuItem > #tMenuItems then
|
|
||||||
nMenuItem = 1
|
|
||||||
end
|
|
||||||
redrawMenu()
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.delete then
|
elseif key == keys.delete and not bReadOnly then
|
||||||
-- Delete
|
|
||||||
if not bMenu and not bReadOnly then
|
|
||||||
local nLimit = #tLines[y] + 1
|
local nLimit = #tLines[y] + 1
|
||||||
if x < nLimit then
|
if x < nLimit then
|
||||||
local sLine = tLines[y]
|
local sLine = tLines[y]
|
||||||
tLines[y] = string.sub(sLine, 1, x - 1) .. string.sub(sLine, x + 1)
|
tLines[y] = string.sub(sLine, 1, x - 1) .. string.sub(sLine, x + 1)
|
||||||
recomplete()
|
recomplete()
|
||||||
redrawLine(y)
|
redrawLines(y)
|
||||||
elseif y < #tLines then
|
elseif y < #tLines then
|
||||||
tLines[y] = tLines[y] .. tLines[y + 1]
|
tLines[y] = tLines[y] .. tLines[y + 1]
|
||||||
table.remove(tLines, y + 1)
|
table.remove(tLines, y + 1)
|
||||||
|
table.remove(tLineLexStates, y + 1)
|
||||||
recomplete()
|
recomplete()
|
||||||
redrawText()
|
redrawText()
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.backspace then
|
elseif key == keys.backspace and not bReadOnly then
|
||||||
-- Backspace
|
|
||||||
if not bMenu and not bReadOnly then
|
|
||||||
if x > 1 then
|
if x > 1 then
|
||||||
-- Remove character
|
-- Remove character
|
||||||
local sLine = tLines[y]
|
local sLine = tLines[y]
|
||||||
@@ -734,14 +686,12 @@ while bRunning do
|
|||||||
local sPrevLen = #tLines[y - 1]
|
local sPrevLen = #tLines[y - 1]
|
||||||
tLines[y - 1] = tLines[y - 1] .. tLines[y]
|
tLines[y - 1] = tLines[y - 1] .. tLines[y]
|
||||||
table.remove(tLines, y)
|
table.remove(tLines, y)
|
||||||
|
table.remove(tLineLexStates, y)
|
||||||
setCursor(sPrevLen + 1, y - 1)
|
setCursor(sPrevLen + 1, y - 1)
|
||||||
redrawText()
|
redrawText()
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.enter or param == keys.numPadEnter then
|
elseif (key == keys.enter or key == keys.numPadEnter) and not bReadOnly then
|
||||||
-- Enter/Numpad Enter
|
|
||||||
if not bMenu and not bReadOnly then
|
|
||||||
-- Newline
|
-- Newline
|
||||||
local sLine = tLines[y]
|
local sLine = tLines[y]
|
||||||
local _, spaces = string.find(sLine, "^[ ]+")
|
local _, spaces = string.find(sLine, "^[ ]+")
|
||||||
@@ -750,99 +700,60 @@ while bRunning do
|
|||||||
end
|
end
|
||||||
tLines[y] = string.sub(sLine, 1, x - 1)
|
tLines[y] = string.sub(sLine, 1, x - 1)
|
||||||
table.insert(tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x))
|
table.insert(tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x))
|
||||||
|
table.insert(tLineLexStates, y + 1, false)
|
||||||
setCursor(spaces + 1, y + 1)
|
setCursor(spaces + 1, y + 1)
|
||||||
redrawText()
|
redrawText()
|
||||||
|
|
||||||
elseif bMenu then
|
elseif key == keys.leftCtrl or key == keys.rightCtrl then
|
||||||
-- Menu selection
|
current_menu = menu.create(menu_items)
|
||||||
doMenuItem(nMenuItem)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif param == keys.leftCtrl or param == keys.rightCtrl then
|
|
||||||
-- Menu toggle
|
|
||||||
bMenu = not bMenu
|
|
||||||
if bMenu then
|
|
||||||
term.setCursorBlink(false)
|
|
||||||
else
|
|
||||||
term.setCursorBlink(true)
|
|
||||||
end
|
|
||||||
redrawMenu()
|
|
||||||
elseif param == keys.rightAlt then
|
|
||||||
if bMenu then
|
|
||||||
bMenu = false
|
|
||||||
term.setCursorBlink(true)
|
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
elseif event[1] == "char" then
|
||||||
elseif sEvent == "char" then
|
if current_menu then
|
||||||
if not bMenu and not bReadOnly then
|
handleMenuEvent(event)
|
||||||
|
elseif not bReadOnly then
|
||||||
-- Input text
|
-- Input text
|
||||||
local sLine = tLines[y]
|
local sLine = tLines[y]
|
||||||
tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x)
|
tLines[y] = string.sub(sLine, 1, x - 1) .. event[2] .. string.sub(sLine, x)
|
||||||
setCursor(x + 1, y)
|
setCursor(x + 1, y)
|
||||||
|
|
||||||
elseif bMenu then
|
|
||||||
-- Select menu items
|
|
||||||
for n, sMenuItem in ipairs(tMenuItems) do
|
|
||||||
if string.lower(string.sub(sMenuItem, 1, 1)) == string.lower(param) then
|
|
||||||
doMenuItem(n)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif sEvent == "paste" then
|
elseif event[1] == "paste" and not bReadOnly then
|
||||||
if not bReadOnly then
|
|
||||||
-- Close menu if open
|
-- Close menu if open
|
||||||
if bMenu then
|
if current_menu then
|
||||||
bMenu = false
|
current_menu = nil
|
||||||
term.setCursorBlink(true)
|
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
end
|
end
|
||||||
-- Input text
|
|
||||||
local sLine = tLines[y]
|
|
||||||
tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x)
|
|
||||||
setCursor(x + #param, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif sEvent == "mouse_click" then
|
-- Input text
|
||||||
local cx, cy = param2, param3
|
local text = event[2]
|
||||||
if not bMenu then
|
local sLine = tLines[y]
|
||||||
if param == 1 then
|
tLines[y] = string.sub(sLine, 1, x - 1) .. text .. string.sub(sLine, x)
|
||||||
|
setCursor(x + #text, y)
|
||||||
|
|
||||||
|
elseif event[1] == "mouse_click" then
|
||||||
|
local button, cx, cy = event[2], event[3], event[4]
|
||||||
|
if current_menu then
|
||||||
|
handleMenuEvent(event)
|
||||||
|
else
|
||||||
|
if button == 1 then
|
||||||
-- Left click
|
-- Left click
|
||||||
if cy < h then
|
if cy < h then
|
||||||
local newY = math.min(math.max(scrollY + cy, 1), #tLines)
|
local newY = math.min(math.max(scrollY + cy, 1), #tLines)
|
||||||
local newX = math.min(math.max(scrollX + cx, 1), #tLines[newY] + 1)
|
local newX = math.min(math.max(scrollX + cx, 1), #tLines[newY] + 1)
|
||||||
setCursor(newX, newY)
|
setCursor(newX, newY)
|
||||||
else
|
else
|
||||||
bMenu = true
|
current_menu = menu.create(menu_items)
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
if cy == h then
|
|
||||||
local nMenuPosEnd = 1
|
|
||||||
local nMenuPosStart = 1
|
|
||||||
for n, sMenuItem in ipairs(tMenuItems) do
|
|
||||||
nMenuPosEnd = nMenuPosEnd + #sMenuItem + 1
|
|
||||||
if cx > nMenuPosStart and cx < nMenuPosEnd then
|
|
||||||
doMenuItem(n)
|
|
||||||
end
|
|
||||||
nMenuPosEnd = nMenuPosEnd + 1
|
|
||||||
nMenuPosStart = nMenuPosEnd
|
|
||||||
end
|
|
||||||
else
|
|
||||||
bMenu = false
|
|
||||||
term.setCursorBlink(true)
|
|
||||||
redrawMenu()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif sEvent == "mouse_scroll" then
|
elseif event[1] == "mouse_scroll" then
|
||||||
if not bMenu then
|
if not current_menu then
|
||||||
if param == -1 then
|
local direction = event[2]
|
||||||
|
if direction == -1 then
|
||||||
-- Scroll up
|
-- Scroll up
|
||||||
if scrollY > 0 then
|
if scrollY > 0 then
|
||||||
-- Move cursor up
|
-- Move cursor up
|
||||||
@@ -850,7 +761,7 @@ while bRunning do
|
|||||||
redrawText()
|
redrawText()
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif param == 1 then
|
elseif direction == 1 then
|
||||||
-- Scroll down
|
-- Scroll down
|
||||||
local nMaxScroll = #tLines - (h - 1)
|
local nMaxScroll = #tLines - (h - 1)
|
||||||
if scrollY < nMaxScroll then
|
if scrollY < nMaxScroll then
|
||||||
@@ -862,7 +773,7 @@ while bRunning do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif sEvent == "term_resize" then
|
elseif event[1] == "term_resize" then
|
||||||
w, h = term.getSize()
|
w, h = term.getSize()
|
||||||
setCursor(x, y)
|
setCursor(x, y)
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
|
@@ -20,6 +20,7 @@ local canvasColour = colours.black
|
|||||||
local canvas = {}
|
local canvas = {}
|
||||||
|
|
||||||
-- The menu options
|
-- The menu options
|
||||||
|
local menu = require "cc.internal.menu"
|
||||||
local mChoices = { "Save", "Exit" }
|
local mChoices = { "Save", "Exit" }
|
||||||
|
|
||||||
-- The message displayed in the footer bar
|
-- The message displayed in the footer bar
|
||||||
@@ -299,10 +300,7 @@ local menu_choices = {
|
|||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end,
|
end,
|
||||||
Exit = function()
|
Exit = function() return true end,
|
||||||
require "cc.internal.event".discard_char() -- Consume stray "char" events from pressing Ctrl then E separately.
|
|
||||||
return true
|
|
||||||
end,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -310,80 +308,25 @@ local menu_choices = {
|
|||||||
returns: true if the program is to be exited; false otherwise
|
returns: true if the program is to be exited; false otherwise
|
||||||
]]
|
]]
|
||||||
local function accessMenu()
|
local function accessMenu()
|
||||||
-- Selected menu option
|
local current_menu = menu.create(mChoices)
|
||||||
local selection = 1
|
|
||||||
|
|
||||||
term.setBackgroundColour(colours.black)
|
term.setBackgroundColour(colours.black)
|
||||||
|
menu.draw(current_menu)
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
-- Draw the menu
|
|
||||||
term.setCursorPos(1, h)
|
|
||||||
term.clearLine()
|
|
||||||
term.setTextColour(colours.white)
|
|
||||||
for k, v in pairs(mChoices) do
|
|
||||||
if selection == k then
|
|
||||||
term.setTextColour(colours.yellow)
|
|
||||||
term.write("[")
|
|
||||||
term.setTextColour(colours.white)
|
|
||||||
term.write(v)
|
|
||||||
term.setTextColour(colours.yellow)
|
|
||||||
term.write("]")
|
|
||||||
term.setTextColour(colours.white)
|
|
||||||
else
|
|
||||||
term.write(" " .. v .. " ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle input in the menu
|
-- Handle input in the menu
|
||||||
local id, param1, param2, param3 = os.pullEvent()
|
local event = table.pack(os.pullEvent())
|
||||||
if id == "key" then
|
|
||||||
local key = param1
|
|
||||||
|
|
||||||
-- Handle menu shortcuts.
|
local result = menu.handle_event(current_menu, table.unpack(event, 1, event.n))
|
||||||
for _, menu_item in ipairs(mChoices) do
|
if result == false then
|
||||||
local k = keys[menu_item:sub(1, 1):lower()]
|
|
||||||
if k and k == key then
|
|
||||||
return menu_choices[menu_item]()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if key == keys.right then
|
|
||||||
-- Move right
|
|
||||||
selection = selection + 1
|
|
||||||
if selection > #mChoices then
|
|
||||||
selection = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif key == keys.left and selection > 1 then
|
|
||||||
-- Move left
|
|
||||||
selection = selection - 1
|
|
||||||
if selection < 1 then
|
|
||||||
selection = #mChoices
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif key == keys.enter or key == keys.numPadEnter then
|
|
||||||
-- Select an option
|
|
||||||
return menu_choices[mChoices[selection]]()
|
|
||||||
elseif key == keys.leftCtrl or keys == keys.rightCtrl then
|
|
||||||
-- Cancel the menu
|
|
||||||
return false
|
return false
|
||||||
|
elseif result ~= nil then
|
||||||
|
return menu_choices[result]()
|
||||||
end
|
end
|
||||||
elseif id == "mouse_click" then
|
|
||||||
local cx, cy = param2, param3
|
|
||||||
if cy ~= h then return false end -- Exit the menu
|
|
||||||
|
|
||||||
local nMenuPosEnd = 1
|
if event[1] == "term_resize" then
|
||||||
local nMenuPosStart = 1
|
|
||||||
for _, sMenuItem in ipairs(mChoices) do
|
|
||||||
nMenuPosEnd = nMenuPosEnd + #sMenuItem + 1
|
|
||||||
if cx > nMenuPosStart and cx < nMenuPosEnd then
|
|
||||||
return menu_choices[sMenuItem]()
|
|
||||||
end
|
|
||||||
nMenuPosEnd = nMenuPosEnd + 1
|
|
||||||
nMenuPosStart = nMenuPosEnd
|
|
||||||
end
|
|
||||||
elseif id == "term_resize" then
|
|
||||||
termResize()
|
termResize()
|
||||||
|
menu.draw(current_menu)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -300,7 +300,7 @@ function shell.setDir(dir)
|
|||||||
sDir = fs.combine(dir, "")
|
sDir = fs.combine(dir, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the path where programs are located.
|
--- Get the path where programs are located.
|
||||||
--
|
--
|
||||||
-- The path is composed of a list of directory names in a string, each separated
|
-- The path is composed of a list of directory names in a string, each separated
|
||||||
-- by a colon (`:`). On normal turtles will look in the current directory (`.`),
|
-- by a colon (`:`). On normal turtles will look in the current directory (`.`),
|
||||||
|
@@ -70,18 +70,33 @@ We expected a closing delimiter (]=]) somewhere after this comment was started.
|
|||||||
1:1-1:5 COMMENT --[=[
|
1:1-1:5 COMMENT --[=[
|
||||||
```
|
```
|
||||||
|
|
||||||
|
But incomplete opening `[`s are treated as a line comment:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
--[
|
||||||
|
--[=
|
||||||
|
return
|
||||||
|
```
|
||||||
|
|
||||||
|
```txt
|
||||||
|
1:1-1:3 COMMENT --[
|
||||||
|
2:1-2:4 COMMENT --[=
|
||||||
|
3:1-3:6 RETURN return
|
||||||
|
```
|
||||||
|
|
||||||
Nested comments are rejected, just as Lua 5.1 does:
|
Nested comments are rejected, just as Lua 5.1 does:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
--[[ [[ ]]
|
--[[ [[ ]] return
|
||||||
```
|
```
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
[[ cannot be nested inside another [[ ... ]]
|
[[ cannot be nested inside another [[ ... ]]
|
||||||
|
|
|
|
||||||
1 | --[[ [[ ]]
|
1 | --[[ [[ ]] return
|
||||||
| ^^
|
| ^^
|
||||||
1:1-1:10 COMMENT --[[ [[ ]]
|
1:1-1:10 COMMENT --[[ [[ ]]
|
||||||
|
1:12-1:17 RETURN return
|
||||||
```
|
```
|
||||||
|
|
||||||
# Strings
|
# Strings
|
||||||
|
@@ -56,7 +56,7 @@ import { type DataExport, WithExport } from "./components/WithExport";
|
|||||||
for (const file of await fs.readdir(sourceDir, { withFileTypes: true, recursive: true })) {
|
for (const file of await fs.readdir(sourceDir, { withFileTypes: true, recursive: true })) {
|
||||||
if(!file.isFile() || !file.name.endsWith(".html")) continue;
|
if(!file.isFile() || !file.name.endsWith(".html")) continue;
|
||||||
|
|
||||||
const sourcePath = path.join(file.path, file.name);
|
const sourcePath = path.join(file.parentPath, file.name);
|
||||||
const contents = await fs.readFile(sourcePath, "utf-8");
|
const contents = await fs.readFile(sourcePath, "utf-8");
|
||||||
|
|
||||||
const { result } = await processor.process(contents);
|
const { result } = await processor.process(contents);
|
||||||
|
Reference in New Issue
Block a user