chore: lsp + format
This commit is contained in:
@@ -13,7 +13,8 @@ namespace {
|
||||
int init(lua_State* state) {
|
||||
std::string name;
|
||||
const bool hasName = optionalString(state, 1, name);
|
||||
return pushStatus(state, Runtime::from(state)->ble().init(hasName ? &name : nullptr));
|
||||
return pushStatus(
|
||||
state, Runtime::from(state)->ble().init(hasName ? &name : nullptr));
|
||||
}
|
||||
|
||||
int deinit(lua_State* state) {
|
||||
@@ -27,7 +28,8 @@ int scan(lua_State* state) {
|
||||
|
||||
std::vector<BleDevice> devices;
|
||||
const Status status = Runtime::from(state)->ble().scan(durationMs, devices);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
|
||||
lua_createtable(state, static_cast<int>(devices.size()), 0);
|
||||
for (size_t at = 0; at < devices.size(); at++) {
|
||||
@@ -59,8 +61,10 @@ int read(lua_State* state) {
|
||||
const std::string service = checkString(state, 1);
|
||||
const std::string characteristic = checkString(state, 2);
|
||||
std::string value;
|
||||
const Status status = Runtime::from(state)->ble().read(service, characteristic, value);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
const Status status =
|
||||
Runtime::from(state)->ble().read(service, characteristic, value);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
pushString(state, value);
|
||||
return 1;
|
||||
}
|
||||
@@ -69,13 +73,15 @@ int write(lua_State* state) {
|
||||
const std::string service = checkString(state, 1);
|
||||
const std::string characteristic = checkString(state, 2);
|
||||
const std::string value = checkString(state, 3);
|
||||
return pushStatus(state, Runtime::from(state)->ble().write(service, characteristic, value));
|
||||
return pushStatus(
|
||||
state, Runtime::from(state)->ble().write(service, characteristic, value));
|
||||
}
|
||||
|
||||
int startAdvertising(lua_State* state) {
|
||||
std::string name;
|
||||
const bool hasName = optionalString(state, 1, name);
|
||||
return pushStatus(state, Runtime::from(state)->ble().startAdvertising(hasName ? &name : nullptr));
|
||||
return pushStatus(state, Runtime::from(state)->ble().startAdvertising(
|
||||
hasName ? &name : nullptr));
|
||||
}
|
||||
|
||||
int stopAdvertising(lua_State* state) {
|
||||
@@ -129,12 +135,12 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerBle(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
lua_setglobal(state, "ble");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @lua-module fs FsLib
|
||||
// @lua-const MAX_READ_BYTES integer 65536 Largest portable whole-file or line read.
|
||||
// @lua-const MAX_READ_BYTES integer 65536 Largest portable whole-file or line
|
||||
// read.
|
||||
|
||||
#include "../helpers.h"
|
||||
|
||||
@@ -11,7 +12,8 @@ constexpr int32_t MAX_READ_BYTES = 65536;
|
||||
|
||||
int32_t checkReadLimit(lua_State* state, int index) {
|
||||
const int32_t maxBytes = checkInt(state, index);
|
||||
luaL_argcheck(state, maxBytes >= 0 && maxBytes <= MAX_READ_BYTES, index, "exceeds fs.MAX_READ_BYTES");
|
||||
luaL_argcheck(state, maxBytes >= 0 && maxBytes <= MAX_READ_BYTES, index,
|
||||
"exceeds fs.MAX_READ_BYTES");
|
||||
return maxBytes;
|
||||
}
|
||||
|
||||
@@ -25,7 +27,8 @@ int fileSize(lua_State* state) {
|
||||
const std::string path = checkString(state, 1);
|
||||
int32_t size = 0;
|
||||
const Status status = Runtime::from(state)->fs().fileSize(path, size);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
lua_pushinteger(state, size);
|
||||
return 1;
|
||||
}
|
||||
@@ -34,8 +37,10 @@ int list(lua_State* state, bool directories) {
|
||||
const std::string path = checkString(state, 1);
|
||||
std::vector<std::string> names;
|
||||
const FsProvider& fs = Runtime::from(state)->fs();
|
||||
const Status status = directories ? fs.listDirs(path, names) : fs.listFiles(path, names);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
const Status status =
|
||||
directories ? fs.listDirs(path, names) : fs.listFiles(path, names);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
pushStrings(state, names);
|
||||
return 1;
|
||||
}
|
||||
@@ -52,8 +57,10 @@ int readFile(lua_State* state) {
|
||||
const int32_t maxBytes = checkReadLimit(state, 2);
|
||||
const std::string path = checkString(state, 1);
|
||||
std::string content;
|
||||
const Status status = Runtime::from(state)->fs().readFile(path, maxBytes, content);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
const Status status =
|
||||
Runtime::from(state)->fs().readFile(path, maxBytes, content);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
pushString(state, content);
|
||||
return 1;
|
||||
}
|
||||
@@ -67,7 +74,8 @@ int readLineAt(lua_State* state) {
|
||||
bool found = false;
|
||||
int32_t nextOffset = 0;
|
||||
std::string line;
|
||||
const Status status = Runtime::from(state)->fs().readLineAt(path, offset, maxBytes, found, line, nextOffset);
|
||||
const Status status = Runtime::from(state)->fs().readLineAt(
|
||||
path, offset, maxBytes, found, line, nextOffset);
|
||||
if (!status.ok) {
|
||||
lua_pushnil(state);
|
||||
lua_pushnil(state);
|
||||
@@ -96,7 +104,8 @@ int removeTree(lua_State* state) {
|
||||
int rename(lua_State* state) {
|
||||
const std::string source = checkString(state, 1);
|
||||
const std::string destination = checkString(state, 2);
|
||||
return pushStatus(state, Runtime::from(state)->fs().rename(source, destination));
|
||||
return pushStatus(state,
|
||||
Runtime::from(state)->fs().rename(source, destination));
|
||||
}
|
||||
|
||||
int writeFile(lua_State* state) {
|
||||
@@ -107,7 +116,8 @@ int writeFile(lua_State* state) {
|
||||
|
||||
const luaL_Reg FUNCTIONS[] = {
|
||||
// --- Whether a path exists.
|
||||
// @param path string Absolute SD-card path; traversal components are rejected.
|
||||
// @param path string Absolute SD-card path; traversal components are
|
||||
// rejected.
|
||||
// @return boolean
|
||||
{"exists", exists},
|
||||
// --- Returns the size of a file in bytes.
|
||||
@@ -132,35 +142,43 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{"mkdir", mkdir},
|
||||
// --- Reads a whole file.
|
||||
// @param path string Absolute file path.
|
||||
// @param maxBytes integer Maximum bytes to allocate, up to fs.MAX_READ_BYTES; oversized files fail rather than truncate.
|
||||
// @param maxBytes integer Maximum bytes to allocate, up to
|
||||
// fs.MAX_READ_BYTES; oversized files fail rather than truncate.
|
||||
// @return string|nil content
|
||||
// @return string|nil error
|
||||
{"readFile", readFile},
|
||||
// --- Reads one line starting at a byte offset.
|
||||
// @param path string Absolute file path.
|
||||
// @param offset integer Zero-based byte offset; a mid-line offset advances to the next line.
|
||||
// @param maxBytes integer Maximum line bytes to allocate, up to fs.MAX_READ_BYTES.
|
||||
// @param offset integer Zero-based byte offset; a mid-line offset advances
|
||||
// to the next line.
|
||||
// @param maxBytes integer Maximum line bytes to allocate, up to
|
||||
// fs.MAX_READ_BYTES.
|
||||
// @return string|nil line Nil at end of file or on failure.
|
||||
// @return integer|nil nextOffset Byte offset of the following line.
|
||||
// @return string|nil error Present when the file cannot be read or the line exceeds maxBytes.
|
||||
// @return string|nil error Present when the file cannot be read or the line
|
||||
// exceeds maxBytes.
|
||||
{"readLineAt", readLineAt},
|
||||
// --- Removes a file.
|
||||
// @param path string Absolute file path. Firmware-protected roots cannot be removed.
|
||||
// @param path string Absolute file path. Firmware-protected roots cannot be
|
||||
// removed.
|
||||
// @return true|nil ok
|
||||
// @return string|nil error
|
||||
{"remove", remove},
|
||||
// --- Removes a directory and everything below it.
|
||||
// @param path string Absolute directory path. Firmware-protected roots cannot be removed.
|
||||
// @param path string Absolute directory path. Firmware-protected roots
|
||||
// cannot be removed.
|
||||
// @return true|nil ok
|
||||
// @return string|nil error
|
||||
{"removeTree", removeTree},
|
||||
// --- Renames a file or directory.
|
||||
// @param source string Absolute source path.
|
||||
// @param destination string Absolute destination path, which must not exist.
|
||||
// @param destination string Absolute destination path, which must not
|
||||
// exist.
|
||||
// @return true|nil ok
|
||||
// @return string|nil error
|
||||
{"rename", rename},
|
||||
// --- Atomically replaces the destination or leaves its previous contents intact.
|
||||
// --- Atomically replaces the destination or leaves its previous contents
|
||||
// intact.
|
||||
// @param path string Absolute file path.
|
||||
// @param content string
|
||||
// @return true|nil ok
|
||||
@@ -169,7 +187,7 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerFs(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
@@ -178,5 +196,5 @@ void registerFs(lua_State* state) {
|
||||
lua_setglobal(state, "fs");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -34,7 +34,8 @@ int getRotation(lua_State* state) {
|
||||
|
||||
int setRotation(lua_State* state) {
|
||||
const int32_t degrees = checkInt(state, 1);
|
||||
luaL_argcheck(state, degrees >= 0 && degrees <= 270 && degrees % 90 == 0, 1, "expected 0, 90, 180, or 270");
|
||||
luaL_argcheck(state, degrees >= 0 && degrees <= 270 && degrees % 90 == 0, 1,
|
||||
"expected 0, 90, 180, or 270");
|
||||
provider(state).setRotation(degrees);
|
||||
return 0;
|
||||
}
|
||||
@@ -59,30 +60,35 @@ int clear(lua_State* state) {
|
||||
}
|
||||
|
||||
int fillRect(lua_State* state) {
|
||||
provider(state).fillRect(checkInt(state, 1), checkInt(state, 2), checkInt(state, 3), checkInt(state, 4),
|
||||
provider(state).fillRect(checkInt(state, 1), checkInt(state, 2),
|
||||
checkInt(state, 3), checkInt(state, 4),
|
||||
checkInt(state, 5));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drawRect(lua_State* state) {
|
||||
provider(state).drawRect(checkInt(state, 1), checkInt(state, 2), checkInt(state, 3), checkInt(state, 4),
|
||||
provider(state).drawRect(checkInt(state, 1), checkInt(state, 2),
|
||||
checkInt(state, 3), checkInt(state, 4),
|
||||
checkInt(state, 5));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drawLine(lua_State* state) {
|
||||
provider(state).drawLine(checkInt(state, 1), checkInt(state, 2), checkInt(state, 3), checkInt(state, 4),
|
||||
provider(state).drawLine(checkInt(state, 1), checkInt(state, 2),
|
||||
checkInt(state, 3), checkInt(state, 4),
|
||||
checkInt(state, 5), optionalInt(state, 6, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drawPixel(lua_State* state) {
|
||||
provider(state).drawPixel(checkInt(state, 1), checkInt(state, 2), checkInt(state, 3));
|
||||
provider(state).drawPixel(checkInt(state, 1), checkInt(state, 2),
|
||||
checkInt(state, 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drawCircle(lua_State* state) {
|
||||
provider(state).drawCircle(checkInt(state, 1), checkInt(state, 2), checkInt(state, 3), checkInt(state, 4),
|
||||
provider(state).drawCircle(checkInt(state, 1), checkInt(state, 2),
|
||||
checkInt(state, 3), checkInt(state, 4),
|
||||
optionalInt(state, 5, 1));
|
||||
return 0;
|
||||
}
|
||||
@@ -94,7 +100,8 @@ int fillCircle(lua_State* state) {
|
||||
const int32_t fill = checkInt(state, 4);
|
||||
int32_t background = 0;
|
||||
const bool hasBackground = optionalColor(state, 5, background);
|
||||
provider(state).fillCircle(x, y, radius, fill, hasBackground ? &background : nullptr);
|
||||
provider(state).fillCircle(x, y, radius, fill,
|
||||
hasBackground ? &background : nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -111,8 +118,10 @@ int roundRect(lua_State* state) {
|
||||
const bool hasTop = optionalColor(state, 7, top);
|
||||
const bool hasBottom = optionalColor(state, 8, bottom);
|
||||
const bool hasBorder = optionalColor(state, 9, border);
|
||||
provider(state).roundRect(x, y, w, h, radius, background, hasTop ? &top : nullptr,
|
||||
hasBottom ? &bottom : (hasTop ? &top : nullptr), hasBorder ? &border : nullptr);
|
||||
provider(state).roundRect(x, y, w, h, radius, background,
|
||||
hasTop ? &top : nullptr,
|
||||
hasBottom ? &bottom : (hasTop ? &top : nullptr),
|
||||
hasBorder ? &border : nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -141,7 +150,8 @@ int fillPolygon(lua_State* state) {
|
||||
luaL_checktype(state, 2, LUA_TTABLE);
|
||||
const int32_t fill = checkInt(state, 3);
|
||||
|
||||
// The vectors are destroyed before any Lua error is raised, because luaL_error longjmps.
|
||||
// The vectors are destroyed before any Lua error is raised, because
|
||||
// luaL_error longjmps.
|
||||
bool usable = false;
|
||||
{
|
||||
std::vector<int32_t> xs;
|
||||
@@ -149,26 +159,31 @@ int fillPolygon(lua_State* state) {
|
||||
readIntegers(state, 1, xs);
|
||||
readIntegers(state, 2, ys);
|
||||
usable = !xs.empty() && xs.size() == ys.size();
|
||||
if (usable) provider(state).fillPolygon(xs.data(), ys.data(), xs.size(), fill);
|
||||
if (usable)
|
||||
provider(state).fillPolygon(xs.data(), ys.data(), xs.size(), fill);
|
||||
}
|
||||
if (!usable) return luaL_error(state, "expected matching non-empty integer arrays");
|
||||
if (!usable)
|
||||
return luaL_error(state, "expected matching non-empty integer arrays");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drawBmp(lua_State* state) {
|
||||
int32_t values[4] = {0, 0, 0, 0};
|
||||
bool present[4] = {false, false, false, false};
|
||||
for (int at = 0; at < 4; at++) present[at] = optionalColor(state, at + 2, values[at]);
|
||||
for (int at = 0; at < 4; at++)
|
||||
present[at] = optionalColor(state, at + 2, values[at]);
|
||||
const std::string path = checkString(state, 1);
|
||||
const Status status = provider(state).drawBmp(path, present[0] ? &values[0] : nullptr,
|
||||
present[1] ? &values[1] : nullptr, present[2] ? &values[2] : nullptr,
|
||||
present[3] ? &values[3] : nullptr);
|
||||
const Status status = provider(state).drawBmp(
|
||||
path, present[0] ? &values[0] : nullptr,
|
||||
present[1] ? &values[1] : nullptr, present[2] ? &values[2] : nullptr,
|
||||
present[3] ? &values[3] : nullptr);
|
||||
return pushStatus(state, status);
|
||||
}
|
||||
|
||||
int getTextWidth(lua_State* state) {
|
||||
const int32_t font = checkInt(state, 1);
|
||||
const int32_t style = optionalInt(state, 3, provider(state).fonts().styleNormal);
|
||||
const int32_t style =
|
||||
optionalInt(state, 3, provider(state).fonts().styleNormal);
|
||||
const std::string text = checkString(state, 2);
|
||||
lua_pushinteger(state, provider(state).textWidth(font, text, style));
|
||||
return 1;
|
||||
@@ -176,7 +191,10 @@ int getTextWidth(lua_State* state) {
|
||||
|
||||
int getFontHeight(lua_State* state) {
|
||||
const int32_t font = checkInt(state, 1);
|
||||
lua_pushinteger(state, provider(state).fontHeight(font, optionalInt(state, 2, provider(state).fonts().styleNormal)));
|
||||
lua_pushinteger(
|
||||
state,
|
||||
provider(state).fontHeight(
|
||||
font, optionalInt(state, 2, provider(state).fonts().styleNormal)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -191,7 +209,8 @@ int drawText(lua_State* state) {
|
||||
int32_t background = 0;
|
||||
const bool hasBackground = optionalColor(state, 7, background);
|
||||
const std::string text = checkString(state, 4);
|
||||
gui.drawText(font, x, y, text, textColor, style, hasBackground ? &background : nullptr);
|
||||
gui.drawText(font, x, y, text, textColor, style,
|
||||
hasBackground ? &background : nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -208,7 +227,8 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
// --- Returns the rotation of the live frame.
|
||||
// @return integer Degrees clockwise for the live frame.
|
||||
{"getRotation", getRotation},
|
||||
// --- Returns an opaque native color. E-ink implementations quantize RGB to available grayscale.
|
||||
// --- Returns an opaque native color. E-ink implementations quantize RGB to
|
||||
// available grayscale.
|
||||
// @param r integer 0 through 255.
|
||||
// @param g integer 0 through 255.
|
||||
// @param b integer 0 through 255.
|
||||
@@ -258,7 +278,8 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
// @param color GuiColor
|
||||
// @param background GuiColor|nil Surface behind an anti-aliased edge.
|
||||
{"fillCircle", fillCircle},
|
||||
// ---Draws an anti-aliased rounded fill, optional gradient, and optional border in one pass.
|
||||
// ---Draws an anti-aliased rounded fill, optional gradient, and optional
|
||||
// border in one pass.
|
||||
// @param x integer
|
||||
// @param y integer
|
||||
// @param w integer
|
||||
@@ -266,7 +287,8 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
// @param radius integer
|
||||
// @param background GuiColor Surface behind the anti-aliased edge.
|
||||
// @param top GuiColor|nil Fill, or gradient top; omitted for no fill.
|
||||
// @param bottom GuiColor|nil Gradient bottom; defaults to top. Panels without a gradient use top.
|
||||
// @param bottom GuiColor|nil Gradient bottom; defaults to top. Panels
|
||||
// without a gradient use top.
|
||||
// @param border GuiColor|nil Omitted for no border.
|
||||
{"roundRect", roundRect},
|
||||
// ---Temporarily gives the app the full panel, including firmware chrome.
|
||||
@@ -309,7 +331,7 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerGui(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
@@ -323,5 +345,5 @@ void registerGui(lua_State* state) {
|
||||
lua_setglobal(state, "gui");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
// @lua-module http HttpLib
|
||||
// @lua-preamble ---@class HttpRequestOptions
|
||||
// @lua-preamble ---@field maxBytes integer Maximum response-body bytes to allocate, up to http.MAX_RESPONSE_BYTES; zero is valid for HEAD.
|
||||
// @lua-preamble ---@field maxBytes integer Maximum response-body bytes to
|
||||
// allocate, up to http.MAX_RESPONSE_BYTES; zero is valid for HEAD.
|
||||
// @lua-preamble ---@field headers? table<string, string>
|
||||
// @lua-preamble
|
||||
// @lua-preamble ---@class HttpResponse
|
||||
// @lua-preamble ---@field status integer HTTP status code.
|
||||
// @lua-preamble ---@field body string Response body, including for non-2xx responses.
|
||||
// @lua-preamble ---@field body string Response body, including for non-2xx
|
||||
// responses.
|
||||
// @lua-preamble
|
||||
// @lua-preamble ---@class HttpDownloadOptions
|
||||
// @lua-preamble ---@field maxBytes integer Required maximum, from 1 through 16777216.
|
||||
// @lua-preamble ---@field maxBytes integer Required maximum, from 1 through
|
||||
// 16777216.
|
||||
// @lua-preamble ---@field expectedSize? integer Exact expected byte count.
|
||||
// @lua-preamble ---@field sha256? string Exact expected SHA-256 as 64 hexadecimal characters.
|
||||
// @lua-const MAX_RESPONSE_BYTES integer 65536 Largest portable in-memory response body.
|
||||
// @lua-preamble ---@field sha256? string Exact expected SHA-256 as 64
|
||||
// hexadecimal characters.
|
||||
// @lua-const MAX_RESPONSE_BYTES integer 65536 Largest portable in-memory
|
||||
// response body.
|
||||
|
||||
#include "../helpers.h"
|
||||
|
||||
@@ -31,12 +36,14 @@ int32_t checkResponseLimit(lua_State* state, int index) {
|
||||
return maxBytes;
|
||||
}
|
||||
|
||||
void readHeaders(lua_State* state, int index, std::vector<HttpHeader>& headers) {
|
||||
void readHeaders(lua_State* state, int index,
|
||||
std::vector<HttpHeader>& headers) {
|
||||
lua_getfield(state, index, "headers");
|
||||
if (lua_istable(state, -1)) {
|
||||
lua_pushnil(state);
|
||||
while (lua_next(state, -2)) {
|
||||
if (lua_type(state, -2) == LUA_TSTRING && lua_type(state, -1) == LUA_TSTRING) {
|
||||
if (lua_type(state, -2) == LUA_TSTRING &&
|
||||
lua_type(state, -1) == LUA_TSTRING) {
|
||||
HttpHeader header;
|
||||
header.name = lua_tostring(state, -2);
|
||||
header.value = lua_tostring(state, -1);
|
||||
@@ -59,8 +66,10 @@ int request(lua_State* state, const char* method, bool withBody) {
|
||||
readHeaders(state, optionsIndex, headers);
|
||||
|
||||
HttpResponse response;
|
||||
const Status status = Runtime::from(state)->http().request(method, url, body, headers, maxBytes, response);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
const Status status = Runtime::from(state)->http().request(
|
||||
method, url, body, headers, maxBytes, response);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
|
||||
lua_createtable(state, 0, 2);
|
||||
setField(state, "status", response.status);
|
||||
@@ -79,14 +88,18 @@ int download(lua_State* state) {
|
||||
lua_getfield(state, 3, "maxBytes");
|
||||
const int32_t maxBytes = static_cast<int32_t>(luaL_checkinteger(state, -1));
|
||||
lua_pop(state, 1);
|
||||
luaL_argcheck(state, maxBytes >= 1 && maxBytes <= MAX_DOWNLOAD_BYTES, 3, "maxBytes must be 1 through 16777216");
|
||||
luaL_argcheck(state, maxBytes >= 1 && maxBytes <= MAX_DOWNLOAD_BYTES, 3,
|
||||
"maxBytes must be 1 through 16777216");
|
||||
|
||||
lua_getfield(state, 3, "expectedSize");
|
||||
const int32_t expectedSize = static_cast<int32_t>(luaL_optinteger(state, -1, 0));
|
||||
const int32_t expectedSize =
|
||||
static_cast<int32_t>(luaL_optinteger(state, -1, 0));
|
||||
lua_pop(state, 1);
|
||||
lua_getfield(state, 3, "sha256");
|
||||
const char* sha256 = lua_isnil(state, -1) ? nullptr : luaL_checkstring(state, -1);
|
||||
luaL_argcheck(state, !sha256 || lua_rawlen(state, -1) == 64, 3, "sha256 must be 64 hexadecimal characters");
|
||||
const char* sha256 =
|
||||
lua_isnil(state, -1) ? nullptr : luaL_checkstring(state, -1);
|
||||
luaL_argcheck(state, !sha256 || lua_rawlen(state, -1) == 64, 3,
|
||||
"sha256 must be 64 hexadecimal characters");
|
||||
|
||||
HttpDownload options;
|
||||
options.maxBytes = maxBytes;
|
||||
@@ -97,8 +110,10 @@ int download(lua_State* state) {
|
||||
const std::string url = checkString(state, 1);
|
||||
const std::string destination = checkString(state, 2);
|
||||
int32_t bytesWritten = 0;
|
||||
const Status status = Runtime::from(state)->http().download(url, destination, options, bytesWritten);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
const Status status = Runtime::from(state)->http().download(
|
||||
url, destination, options, bytesWritten);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
lua_pushinteger(state, bytesWritten);
|
||||
return 1;
|
||||
}
|
||||
@@ -112,8 +127,9 @@ int urlencode(lua_State* state) {
|
||||
luaL_buffinit(state, &buffer);
|
||||
for (size_t at = 0; at < length; at++) {
|
||||
const unsigned char c = static_cast<unsigned char>(input[at]);
|
||||
const bool unreserved = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' ||
|
||||
c == '_' || c == '.' || c == '~';
|
||||
const bool unreserved = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '-' || c == '_' ||
|
||||
c == '.' || c == '~';
|
||||
if (unreserved) {
|
||||
luaL_addchar(&buffer, static_cast<char>(c));
|
||||
} else {
|
||||
@@ -131,7 +147,8 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
// @param url string
|
||||
// @param options HttpRequestOptions
|
||||
// @return HttpResponse|nil response
|
||||
// @return string|nil error Transport failure or response body exceeding maxBytes.
|
||||
// @return string|nil error Transport failure or response body exceeding
|
||||
// maxBytes.
|
||||
{"get", get},
|
||||
// --- Performs a HEAD request.
|
||||
// @param url string
|
||||
@@ -159,7 +176,8 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
// @return HttpResponse|nil response
|
||||
// @return string|nil error
|
||||
{"patch", patch},
|
||||
// --- Streams authenticated HTTPS to a new file and removes partial or unverified output.
|
||||
// --- Streams authenticated HTTPS to a new file and removes partial or
|
||||
// unverified output.
|
||||
// @param url string HTTPS URL.
|
||||
// @param destination string Absolute path which must not exist.
|
||||
// @param options HttpDownloadOptions
|
||||
@@ -173,7 +191,7 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerHttp(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
@@ -182,5 +200,5 @@ void registerHttp(lua_State* state) {
|
||||
lua_setglobal(state, "http");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -33,12 +33,12 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerLog(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
lua_setglobal(state, "log");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -20,13 +20,15 @@
|
||||
// @lua-preamble
|
||||
// @lua-preamble ---@class NodeStyle
|
||||
// @lua-preamble ---@field color? GuiColor
|
||||
// @lua-preamble ---@field background? GuiColor Background offered to descendants.
|
||||
// @lua-preamble ---@field background? GuiColor Background offered to
|
||||
// descendants.
|
||||
// @lua-preamble ---@field fill? GuiColor Surface painted by a box.
|
||||
// @lua-preamble ---@field border? GuiColor
|
||||
// @lua-preamble ---@field face? GuiColor Default button surface.
|
||||
// @lua-preamble ---@field pressedFace? GuiColor Pressed button surface.
|
||||
// @lua-preamble ---@field pressedColor? GuiColor Pressed button text.
|
||||
// @lua-preamble ---@field focusColor? GuiColor Distinct outline for directional focus.
|
||||
// @lua-preamble ---@field focusColor? GuiColor Distinct outline for directional
|
||||
// focus.
|
||||
// @lua-preamble ---@field radius? integer
|
||||
// @lua-preamble ---@field font? GuiFont
|
||||
// @lua-preamble ---@field textStyle? GuiTextStyle
|
||||
@@ -46,26 +48,32 @@ ui::Tree& tree(lua_State* state) { return Runtime::from(state)->tree(); }
|
||||
|
||||
uint16_t checkNode(lua_State* state, int index) {
|
||||
const lua_Integer id = luaL_checkinteger(state, index);
|
||||
luaL_argcheck(state, id >= 0 && static_cast<size_t>(id) < tree(state).nodes.size(), index, "unknown node");
|
||||
luaL_argcheck(state,
|
||||
id >= 0 && static_cast<size_t>(id) < tree(state).nodes.size(),
|
||||
index, "unknown node");
|
||||
return static_cast<uint16_t>(id);
|
||||
}
|
||||
|
||||
// A number below one is a fraction of the parent, kept as per-mille so the firmware and
|
||||
// the host round a layout identically.
|
||||
// A number below one is a fraction of the parent, kept as per-mille so the
|
||||
// firmware and the host round a layout identically.
|
||||
ui::Size sizeAt(lua_State* state, int index, bool& present) {
|
||||
present = !lua_isnoneornil(state, index);
|
||||
ui::Size size;
|
||||
if (!present) return size;
|
||||
if (!present)
|
||||
return size;
|
||||
if (lua_type(state, index) == LUA_TSTRING) {
|
||||
const char* mode = lua_tostring(state, index);
|
||||
if (strcmp(mode, "fill") == 0) return ui::Size::fill();
|
||||
if (strcmp(mode, "auto") == 0) return size;
|
||||
if (strcmp(mode, "fill") == 0)
|
||||
return ui::Size::fill();
|
||||
if (strcmp(mode, "auto") == 0)
|
||||
return size;
|
||||
luaL_error(state, "size must be a number, 'fill', or 'auto'");
|
||||
return size;
|
||||
}
|
||||
const lua_Number value = luaL_checknumber(state, index);
|
||||
return value > 0.0 && value < 1.0 ? ui::Size::fraction(static_cast<int16_t>(value * 1000.0))
|
||||
: ui::Size::px(static_cast<int16_t>(value));
|
||||
return value > 0.0 && value < 1.0
|
||||
? ui::Size::fraction(static_cast<int16_t>(value * 1000.0))
|
||||
: ui::Size::px(static_cast<int16_t>(value));
|
||||
}
|
||||
|
||||
ui::Size readSize(lua_State* state, int index, const char* key, bool& present) {
|
||||
@@ -75,9 +83,12 @@ ui::Size readSize(lua_State* state, int index, const char* key, bool& present) {
|
||||
return size;
|
||||
}
|
||||
|
||||
int16_t readNumber(lua_State* state, int index, const char* key, int16_t fallback) {
|
||||
int16_t readNumber(lua_State* state, int index, const char* key,
|
||||
int16_t fallback) {
|
||||
lua_getfield(state, index, key);
|
||||
const int16_t value = lua_isnoneornil(state, -1) ? fallback : static_cast<int16_t>(luaL_checknumber(state, -1));
|
||||
const int16_t value = lua_isnoneornil(state, -1)
|
||||
? fallback
|
||||
: static_cast<int16_t>(luaL_checknumber(state, -1));
|
||||
lua_pop(state, 1);
|
||||
return value;
|
||||
}
|
||||
@@ -100,8 +111,8 @@ ui::Align readAlign(lua_State* state, int index, const char* key) {
|
||||
align = ui::END;
|
||||
} else if (strcmp(value, "between") == 0) {
|
||||
align = ui::BETWEEN;
|
||||
// "stretch" is the default cross-axis behaviour: a child without its own size
|
||||
// already fills the line.
|
||||
// "stretch" is the default cross-axis behaviour: a child without its own
|
||||
// size already fills the line.
|
||||
} else if (strcmp(value, "start") != 0 && strcmp(value, "stretch") != 0) {
|
||||
lua_pop(state, 1);
|
||||
luaL_error(state, "unknown alignment '%s'", value);
|
||||
@@ -160,17 +171,22 @@ int create(lua_State* state) {
|
||||
lua_pop(state, 1);
|
||||
|
||||
uint8_t flags = 0;
|
||||
if (readFlag(state, 2, "row")) flags |= ui::ROW;
|
||||
if (readFlag(state, 2, "capture")) flags |= ui::CAPTURE;
|
||||
if (readFlag(state, 2, "interactive")) flags |= ui::INTERACTIVE;
|
||||
if (readFlag(state, 2, "row"))
|
||||
flags |= ui::ROW;
|
||||
if (readFlag(state, 2, "capture"))
|
||||
flags |= ui::CAPTURE;
|
||||
if (readFlag(state, 2, "interactive"))
|
||||
flags |= ui::INTERACTIVE;
|
||||
|
||||
lua_getfield(state, 2, "font");
|
||||
const int32_t font = lua_isnoneornil(state, -1) ? Runtime::from(state)->gui().fonts().ui
|
||||
: static_cast<int32_t>(luaL_checkinteger(state, -1));
|
||||
const int32_t font = lua_isnoneornil(state, -1)
|
||||
? Runtime::from(state)->gui().fonts().ui
|
||||
: static_cast<int32_t>(luaL_checkinteger(state, -1));
|
||||
lua_pop(state, 1);
|
||||
|
||||
lua_getfield(state, 2, "label");
|
||||
const char* label = lua_isnoneornil(state, -1) ? nullptr : luaL_checkstring(state, -1);
|
||||
const char* label =
|
||||
lua_isnoneornil(state, -1) ? nullptr : luaL_checkstring(state, -1);
|
||||
if (label && type == ui::TEXT) {
|
||||
GuiProvider& gui = Runtime::from(state)->gui();
|
||||
const int32_t style = gui.fonts().styleNormal;
|
||||
@@ -179,7 +195,8 @@ int create(lua_State* state) {
|
||||
}
|
||||
|
||||
const uint16_t id = tree(state).add(parent, spec, type, flags);
|
||||
if (label) tree(state).setLabel(id, label);
|
||||
if (label)
|
||||
tree(state).setLabel(id, label);
|
||||
lua_pop(state, 1);
|
||||
lua_pushinteger(state, id);
|
||||
return 1;
|
||||
@@ -188,22 +205,26 @@ int create(lua_State* state) {
|
||||
int attach(lua_State* state) {
|
||||
const uint16_t parent = checkNode(state, 1);
|
||||
const uint16_t child = checkNode(state, 2);
|
||||
luaL_argcheck(state, tree(state).nodes[child].parent == ui::NONE, 2, "already attached");
|
||||
luaL_argcheck(state, tree(state).nodes[child].parent == ui::NONE, 2,
|
||||
"already attached");
|
||||
tree(state).attach(parent, child);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setSize(lua_State* state) {
|
||||
const uint16_t id = checkNode(state, 1);
|
||||
luaL_argcheck(state, id < tree(state).specs.size(), 1, "layout scratch has been dropped");
|
||||
luaL_argcheck(state, id < tree(state).specs.size(), 1,
|
||||
"layout scratch has been dropped");
|
||||
bool hasW = false;
|
||||
bool hasH = false;
|
||||
const ui::Size w = sizeAt(state, 2, hasW);
|
||||
const ui::Size h = sizeAt(state, 3, hasH);
|
||||
|
||||
ui::Spec& spec = tree(state).specs[id];
|
||||
if (hasW) spec.w = w;
|
||||
if (hasH) spec.h = h;
|
||||
if (hasW)
|
||||
spec.w = w;
|
||||
if (hasH)
|
||||
spec.h = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -214,7 +235,8 @@ int layout(lua_State* state) {
|
||||
const int32_t w = checkInt(state, 4);
|
||||
const int32_t h = checkInt(state, 5);
|
||||
ui::Tree& nodes = tree(state);
|
||||
luaL_argcheck(state, root < nodes.specs.size(), 1, "layout scratch has been dropped");
|
||||
luaL_argcheck(state, root < nodes.specs.size(), 1,
|
||||
"layout scratch has been dropped");
|
||||
if (nodes.layout(root, x, y, w, h)) {
|
||||
lua_pushboolean(state, true);
|
||||
return 1;
|
||||
@@ -231,8 +253,10 @@ int dropScratch(lua_State* state) {
|
||||
|
||||
int hit(lua_State* state) {
|
||||
const uint16_t root = checkNode(state, 1);
|
||||
const uint16_t found = tree(state).hit(root, checkInt(state, 2), checkInt(state, 3));
|
||||
if (found == ui::NONE) return 0;
|
||||
const uint16_t found =
|
||||
tree(state).hit(root, checkInt(state, 2), checkInt(state, 3));
|
||||
if (found == ui::NONE)
|
||||
return 0;
|
||||
lua_pushinteger(state, found);
|
||||
return 1;
|
||||
}
|
||||
@@ -256,19 +280,22 @@ int setLabel(lua_State* state) {
|
||||
|
||||
int getLabel(lua_State* state) {
|
||||
const char* label = tree(state).label(checkNode(state, 1));
|
||||
if (!label) return 0;
|
||||
if (!label)
|
||||
return 0;
|
||||
lua_pushstring(state, label);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getParent(lua_State* state) {
|
||||
const uint16_t parent = tree(state).nodes[checkNode(state, 1)].parent;
|
||||
if (parent == ui::NONE) return 0;
|
||||
if (parent == ui::NONE)
|
||||
return 0;
|
||||
lua_pushinteger(state, parent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void readStyleColor(lua_State* state, int index, const char* key, int32_t& field, uint16_t flag, uint16_t& set) {
|
||||
void readStyleColor(lua_State* state, int index, const char* key,
|
||||
int32_t& field, uint16_t flag, uint16_t& set) {
|
||||
lua_getfield(state, index, key);
|
||||
if (!lua_isnoneornil(state, -1)) {
|
||||
field = static_cast<int32_t>(luaL_checkinteger(state, -1));
|
||||
@@ -287,11 +314,15 @@ int setStyle(lua_State* state) {
|
||||
readStyleColor(state, 2, "fill", style.fill, ui::S_FILL, style.set);
|
||||
readStyleColor(state, 2, "border", style.border, ui::S_BORDER, style.set);
|
||||
readStyleColor(state, 2, "face", style.face, ui::S_FACE, style.set);
|
||||
readStyleColor(state, 2, "pressedFace", style.pressedFace, ui::S_PRESSED_FACE, style.set);
|
||||
readStyleColor(state, 2, "pressedColor", style.pressedColor, ui::S_PRESSED_COLOR, style.set);
|
||||
readStyleColor(state, 2, "focusColor", style.focusColor, ui::S_FOCUS_COLOR, style.set);
|
||||
readStyleColor(state, 2, "pressedFace", style.pressedFace, ui::S_PRESSED_FACE,
|
||||
style.set);
|
||||
readStyleColor(state, 2, "pressedColor", style.pressedColor,
|
||||
ui::S_PRESSED_COLOR, style.set);
|
||||
readStyleColor(state, 2, "focusColor", style.focusColor, ui::S_FOCUS_COLOR,
|
||||
style.set);
|
||||
readStyleColor(state, 2, "font", style.font, ui::S_FONT, style.set);
|
||||
readStyleColor(state, 2, "textStyle", style.textStyle, ui::S_TEXT_STYLE, style.set);
|
||||
readStyleColor(state, 2, "textStyle", style.textStyle, ui::S_TEXT_STYLE,
|
||||
style.set);
|
||||
|
||||
int32_t radius = style.radius;
|
||||
readStyleColor(state, 2, "radius", radius, ui::S_RADIUS, style.set);
|
||||
@@ -321,30 +352,37 @@ int setPressed(lua_State* state) {
|
||||
}
|
||||
|
||||
int isPressed(lua_State* state) {
|
||||
lua_pushboolean(state, (tree(state).nodes[checkNode(state, 1)].flags & ui::PRESSED) != 0);
|
||||
lua_pushboolean(
|
||||
state, (tree(state).nodes[checkNode(state, 1)].flags & ui::PRESSED) != 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t firstInteractive(const ui::Tree& nodes, uint16_t id) {
|
||||
if (nodes.nodes[id].flags & ui::INTERACTIVE) return id;
|
||||
for (uint16_t child = nodes.nodes[id].first; child != ui::NONE; child = nodes.nodes[child].next) {
|
||||
if (nodes.nodes[id].flags & ui::INTERACTIVE)
|
||||
return id;
|
||||
for (uint16_t child = nodes.nodes[id].first; child != ui::NONE;
|
||||
child = nodes.nodes[child].next) {
|
||||
const uint16_t found = firstInteractive(nodes, child);
|
||||
if (found != ui::NONE) return found;
|
||||
if (found != ui::NONE)
|
||||
return found;
|
||||
}
|
||||
return ui::NONE;
|
||||
}
|
||||
|
||||
void setFocusTo(ui::Tree& nodes, uint16_t id) {
|
||||
if (nodes.focus != ui::NONE) nodes.nodes[nodes.focus].flags |= ui::DIRTY;
|
||||
if (nodes.focus != ui::NONE)
|
||||
nodes.nodes[nodes.focus].flags |= ui::DIRTY;
|
||||
nodes.focus = id;
|
||||
if (id != ui::NONE) nodes.nodes[id].flags |= ui::DIRTY;
|
||||
if (id != ui::NONE)
|
||||
nodes.nodes[id].flags |= ui::DIRTY;
|
||||
}
|
||||
|
||||
int focusFirst(lua_State* state) {
|
||||
ui::Tree& nodes = tree(state);
|
||||
const uint16_t found = firstInteractive(nodes, checkNode(state, 1));
|
||||
setFocusTo(nodes, found);
|
||||
if (found == ui::NONE) return 0;
|
||||
if (found == ui::NONE)
|
||||
return 0;
|
||||
lua_pushinteger(state, found);
|
||||
return 1;
|
||||
}
|
||||
@@ -357,16 +395,17 @@ int setFocus(lua_State* state) {
|
||||
|
||||
int getFocus(lua_State* state) {
|
||||
const uint16_t focus = tree(state).focus;
|
||||
if (focus == ui::NONE) return 0;
|
||||
if (focus == ui::NONE)
|
||||
return 0;
|
||||
lua_pushinteger(state, focus);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Nearest candidate strictly beyond the current node's edge, scored by the gap along the
|
||||
// travel axis plus the misalignment across it, so a directly adjacent control always
|
||||
// beats a distant one that happens to line up.
|
||||
void collectCandidate(const ui::Tree& nodes, uint16_t id, const ui::Node& from, const char* direction,
|
||||
uint16_t& best, long& bestScore) {
|
||||
// Nearest candidate strictly beyond the current node's edge, scored by the gap
|
||||
// along the travel axis plus the misalignment across it, so a directly adjacent
|
||||
// control always beats a distant one that happens to line up.
|
||||
void collectCandidate(const ui::Tree& nodes, uint16_t id, const ui::Node& from,
|
||||
const char* direction, uint16_t& best, long& bestScore) {
|
||||
const ui::Node& node = nodes.nodes[id];
|
||||
if ((node.flags & ui::INTERACTIVE) && id != nodes.focus) {
|
||||
const long dx = (node.x + node.w / 2) - (from.x + from.w / 2);
|
||||
@@ -399,7 +438,8 @@ void collectCandidate(const ui::Tree& nodes, uint16_t id, const ui::Node& from,
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint16_t child = nodes.nodes[id].first; child != ui::NONE; child = nodes.nodes[child].next) {
|
||||
for (uint16_t child = nodes.nodes[id].first; child != ui::NONE;
|
||||
child = nodes.nodes[child].next) {
|
||||
collectCandidate(nodes, child, from, direction, best, bestScore);
|
||||
}
|
||||
}
|
||||
@@ -407,18 +447,22 @@ void collectCandidate(const ui::Tree& nodes, uint16_t id, const ui::Node& from,
|
||||
int moveFocus(lua_State* state) {
|
||||
const uint16_t root = checkNode(state, 1);
|
||||
const char* direction = luaL_checkstring(state, 2);
|
||||
luaL_argcheck(state,
|
||||
strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0 || strcmp(direction, "left") == 0 ||
|
||||
strcmp(direction, "right") == 0,
|
||||
2, "expected up, down, left, or right");
|
||||
luaL_argcheck(
|
||||
state,
|
||||
strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0 ||
|
||||
strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0,
|
||||
2, "expected up, down, left, or right");
|
||||
|
||||
ui::Tree& nodes = tree(state);
|
||||
if (nodes.focus == ui::NONE) return focusFirst(state);
|
||||
if (nodes.focus == ui::NONE)
|
||||
return focusFirst(state);
|
||||
|
||||
uint16_t best = ui::NONE;
|
||||
long bestScore = 0;
|
||||
collectCandidate(nodes, root, nodes.nodes[nodes.focus], direction, best, bestScore);
|
||||
if (best != ui::NONE) setFocusTo(nodes, best);
|
||||
collectCandidate(nodes, root, nodes.nodes[nodes.focus], direction, best,
|
||||
bestScore);
|
||||
if (best != ui::NONE)
|
||||
setFocusTo(nodes, best);
|
||||
lua_pushinteger(state, nodes.focus);
|
||||
return 1;
|
||||
}
|
||||
@@ -436,7 +480,9 @@ void callPainter(void* context, uint16_t id, int x, int y, int w, int h) {
|
||||
lua_pushinteger(state, w);
|
||||
lua_pushinteger(state, h);
|
||||
if (lua_pcall(state, 5, 0, 0) != LUA_OK) {
|
||||
Runtime::from(state)->log().write(LogLevel::Error, lua_tostring(state, -1) ? lua_tostring(state, -1) : "painter");
|
||||
Runtime::from(state)->log().write(
|
||||
LogLevel::Error,
|
||||
lua_tostring(state, -1) ? lua_tostring(state, -1) : "painter");
|
||||
lua_pop(state, 1);
|
||||
}
|
||||
}
|
||||
@@ -545,15 +591,18 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
// --- Returns the focused node.
|
||||
// @return NodeId|nil
|
||||
{"getFocus", getFocus},
|
||||
// --- Moves to the nearest interactive node in the requested direction without wrapping.
|
||||
// --- Moves to the nearest interactive node in the requested direction
|
||||
// without wrapping.
|
||||
// @param root NodeId
|
||||
// @param direction NodeDirection
|
||||
// @return NodeId|nil focused Current focus when no candidate exists.
|
||||
{"moveFocus", moveFocus},
|
||||
// --- Registers the painter every custom node calls.
|
||||
// @param painter fun(id: NodeId, x: integer, y: integer, w: integer, h: integer)
|
||||
// @param painter fun(id: NodeId, x: integer, y: integer, w: integer, h:
|
||||
// integer)
|
||||
{"setPainter", setPainter},
|
||||
// --- Paints dirty nodes; the firmware owns publication to the physical display.
|
||||
// --- Paints dirty nodes; the firmware owns publication to the physical
|
||||
// display.
|
||||
// @param root NodeId
|
||||
{"draw", draw},
|
||||
// --- Returns the number of nodes in the tree.
|
||||
@@ -565,12 +614,12 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerNode(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
lua_setglobal(state, "node");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -30,7 +30,8 @@ int setRotation(lua_State* state) {
|
||||
const lua_Integer degrees = luaL_checkinteger(state, 1);
|
||||
luaL_argcheck(state, degrees >= 0 && degrees <= 270 && degrees % 90 == 0, 1,
|
||||
"expected 0, 90, 180, or 270");
|
||||
return pushStatus(state, Runtime::from(state)->settings().setRotation(degrees));
|
||||
return pushStatus(state,
|
||||
Runtime::from(state)->settings().setRotation(degrees));
|
||||
}
|
||||
|
||||
int getTimezone(lua_State* state) {
|
||||
@@ -42,7 +43,8 @@ int getTimezone(lua_State* state) {
|
||||
int setTimezone(lua_State* state) {
|
||||
size_t length = 0;
|
||||
const char* value = luaL_checklstring(state, 1, &length);
|
||||
return pushStatus(state, Runtime::from(state)->settings().setTimezone({value, length}));
|
||||
return pushStatus(
|
||||
state, Runtime::from(state)->settings().setTimezone({value, length}));
|
||||
}
|
||||
|
||||
const luaL_Reg FUNCTIONS[] = {
|
||||
@@ -65,12 +67,12 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerSettings(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
lua_setglobal(state, "settings");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -7,23 +7,49 @@ namespace esp32lua {
|
||||
namespace bindings {
|
||||
namespace {
|
||||
|
||||
int getAPIVersion(lua_State* state) { lua_pushinteger(state, API_VERSION); return 1; }
|
||||
int hasFeature(lua_State* state) { lua_pushboolean(state, Runtime::from(state)->hasFeature(luaL_checkstring(state, 1))); return 1; }
|
||||
int getMillis(lua_State* state) { lua_pushinteger(state, Runtime::from(state)->sys().millis()); return 1; }
|
||||
int getAppID(lua_State* state) { pushString(state, Runtime::from(state)->appId()); return 1; }
|
||||
int getAppTitle(lua_State* state) { pushString(state, Runtime::from(state)->appTitle()); return 1; }
|
||||
int getAppDataPath(lua_State* state) { pushString(state, Runtime::from(state)->appDataPath()); return 1; }
|
||||
int setAppTitle(lua_State* state) { Runtime::from(state)->setAppTitle(luaL_checkstring(state, 1)); return 0; }
|
||||
int getAPIVersion(lua_State* state) {
|
||||
lua_pushinteger(state, API_VERSION);
|
||||
return 1;
|
||||
}
|
||||
int hasFeature(lua_State* state) {
|
||||
lua_pushboolean(state,
|
||||
Runtime::from(state)->hasFeature(luaL_checkstring(state, 1)));
|
||||
return 1;
|
||||
}
|
||||
int getMillis(lua_State* state) {
|
||||
lua_pushinteger(state, Runtime::from(state)->sys().millis());
|
||||
return 1;
|
||||
}
|
||||
int getAppID(lua_State* state) {
|
||||
pushString(state, Runtime::from(state)->appId());
|
||||
return 1;
|
||||
}
|
||||
int getAppTitle(lua_State* state) {
|
||||
pushString(state, Runtime::from(state)->appTitle());
|
||||
return 1;
|
||||
}
|
||||
int getAppDataPath(lua_State* state) {
|
||||
pushString(state, Runtime::from(state)->appDataPath());
|
||||
return 1;
|
||||
}
|
||||
int setAppTitle(lua_State* state) {
|
||||
Runtime::from(state)->setAppTitle(luaL_checkstring(state, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int navigate(lua_State* state, bool replace) {
|
||||
const std::string path = checkString(state, 1);
|
||||
const std::string arg = lua_isnoneornil(state, 2) ? std::string() : checkString(state, 2);
|
||||
const std::string arg =
|
||||
lua_isnoneornil(state, 2) ? std::string() : checkString(state, 2);
|
||||
Runtime::from(state)->requestLaunch(path, arg, replace);
|
||||
return 0;
|
||||
}
|
||||
int launch(lua_State* state) { return navigate(state, false); }
|
||||
int replace(lua_State* state) { return navigate(state, true); }
|
||||
int back(lua_State* state) { Runtime::from(state)->requestBack(); return 0; }
|
||||
int back(lua_State* state) {
|
||||
Runtime::from(state)->requestBack();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getMemory(lua_State* state) {
|
||||
const MemoryInfo memory = Runtime::from(state)->sys().memory();
|
||||
@@ -32,7 +58,10 @@ int getMemory(lua_State* state) {
|
||||
lua_pushinteger(state, memory.largestFreeBlock);
|
||||
return 3;
|
||||
}
|
||||
int isClockSynced(lua_State* state) { lua_pushboolean(state, Runtime::from(state)->sys().isClockSynced()); return 1; }
|
||||
int isClockSynced(lua_State* state) {
|
||||
lua_pushboolean(state, Runtime::from(state)->sys().isClockSynced());
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg FUNCTIONS[] = {
|
||||
// --- Returns the implemented API contract version.
|
||||
@@ -51,8 +80,10 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
// --- Returns the running app title, initially the app ID.
|
||||
// @return string
|
||||
{"getAppTitle", getAppTitle},
|
||||
// --- Returns the current app's guaranteed-existing persistent data directory.
|
||||
// @return string Absolute path under /.lua/data, preserved across app updates.
|
||||
// --- Returns the current app's guaranteed-existing persistent data
|
||||
// directory.
|
||||
// @return string Absolute path under /.lua/data, preserved across app
|
||||
// updates.
|
||||
{"getAppDataPath", getAppDataPath},
|
||||
// --- Changes the running app's display title.
|
||||
// @param title string
|
||||
@@ -78,7 +109,10 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
void registerSys(lua_State* state) { luaL_newlib(state, FUNCTIONS); lua_setglobal(state, "sys"); }
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace
|
||||
void registerSys(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
lua_setglobal(state, "sys");
|
||||
}
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -15,8 +15,10 @@ int schedule(lua_State* state, bool repeating) {
|
||||
|
||||
lua_pushvalue(state, 2);
|
||||
const int callbackRef = luaL_ref(state, LUA_REGISTRYINDEX);
|
||||
const TimerId id = Runtime::from(state)->addTimer(callbackRef, intervalMs, repeating);
|
||||
if (id == 0) return luaL_error(state, "no timer slot available");
|
||||
const TimerId id =
|
||||
Runtime::from(state)->addTimer(callbackRef, intervalMs, repeating);
|
||||
if (id == 0)
|
||||
return luaL_error(state, "no timer slot available");
|
||||
lua_pushinteger(state, id);
|
||||
return 1;
|
||||
}
|
||||
@@ -31,12 +33,14 @@ int cancel(lua_State* state) {
|
||||
|
||||
const luaL_Reg FUNCTIONS[] = {
|
||||
// --- Runs a callback once after a delay.
|
||||
// @param intervalMs integer Positive delay; callback timing is best effort and never early.
|
||||
// @param intervalMs integer Positive delay; callback timing is best effort
|
||||
// and never early.
|
||||
// @param callback TimerCallback Retained until it fires or is cancelled.
|
||||
// @return TimerId
|
||||
{"after", after},
|
||||
// --- Runs a callback repeatedly.
|
||||
// @param intervalMs integer Positive interval; callback timing is best effort and never early.
|
||||
// @param intervalMs integer Positive interval; callback timing is best
|
||||
// effort and never early.
|
||||
// @param callback TimerCallback Retained until cancelled.
|
||||
// @return TimerId
|
||||
{"every", every},
|
||||
@@ -47,12 +51,12 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerTimer(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
lua_setglobal(state, "timer");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
// @lua-preamble ---@field rssi integer
|
||||
// @lua-preamble ---@field secure boolean
|
||||
// @lua-preamble
|
||||
// @lua-preamble ---@alias WifiState "disconnected"|"connecting"|"connected"|"not_found"|"failed"
|
||||
// @lua-preamble ---@alias WifiState
|
||||
// "disconnected"|"connecting"|"connected"|"not_found"|"failed"
|
||||
// @lua-preamble
|
||||
// @lua-preamble ---@class WifiStatus
|
||||
// @lua-preamble ---@field state WifiState
|
||||
@@ -21,7 +22,8 @@ namespace {
|
||||
int scan(lua_State* state) {
|
||||
std::vector<WifiNetwork> networks;
|
||||
const Status status = Runtime::from(state)->wifi().scan(networks);
|
||||
if (!status.ok) return pushError(state, status.error);
|
||||
if (!status.ok)
|
||||
return pushError(state, status.error);
|
||||
|
||||
lua_createtable(state, static_cast<int>(networks.size()), 0);
|
||||
for (size_t at = 0; at < networks.size(); at++) {
|
||||
@@ -39,8 +41,8 @@ int connect(lua_State* state) {
|
||||
std::string password;
|
||||
const bool hasSsid = optionalString(state, 1, ssid);
|
||||
const bool hasPassword = optionalString(state, 2, password);
|
||||
const Status status =
|
||||
Runtime::from(state)->wifi().connect(hasSsid ? &ssid : nullptr, hasPassword ? &password : nullptr);
|
||||
const Status status = Runtime::from(state)->wifi().connect(
|
||||
hasSsid ? &ssid : nullptr, hasPassword ? &password : nullptr);
|
||||
return pushStatus(state, status);
|
||||
}
|
||||
|
||||
@@ -55,7 +57,8 @@ int getStatus(lua_State* state) {
|
||||
}
|
||||
|
||||
int isConnected(lua_State* state) {
|
||||
lua_pushboolean(state, Runtime::from(state)->wifi().status().state == "connected");
|
||||
lua_pushboolean(state,
|
||||
Runtime::from(state)->wifi().status().state == "connected");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -70,14 +73,17 @@ int disconnect(lua_State* state) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int forget(lua_State* state) { return pushStatus(state, Runtime::from(state)->wifi().forget()); }
|
||||
int forget(lua_State* state) {
|
||||
return pushStatus(state, Runtime::from(state)->wifi().forget());
|
||||
}
|
||||
|
||||
const luaL_Reg FUNCTIONS[] = {
|
||||
// --- Scans for visible networks.
|
||||
// @return WifiNetwork[]|nil networks
|
||||
// @return string|nil error
|
||||
{"scan", scan},
|
||||
// --- With credentials, saves and joins that network. Without them, reconnects saved credentials.
|
||||
// --- With credentials, saves and joins that network. Without them,
|
||||
// reconnects saved credentials.
|
||||
// @param ssid string|nil
|
||||
// @param password string|nil Omit for an open network.
|
||||
// @return true|nil ok
|
||||
@@ -101,12 +107,12 @@ const luaL_Reg FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerWifi(lua_State* state) {
|
||||
luaL_newlib(state, FUNCTIONS);
|
||||
lua_setglobal(state, "wifi");
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
@@ -35,10 +35,13 @@ int wasReleased(lua_State* state) {
|
||||
// @lua-augment input InputLib
|
||||
// @lua-preamble ---@alias Button "up"|"down"|"left"|"right"|"confirm"|"back"
|
||||
// @lua-preamble
|
||||
// @lua-preamble -- Roles, not physical buttons: a device maps whatever hardware it has onto them, and
|
||||
// @lua-preamble -- up/down/left/right are the directions node.moveFocus already takes.
|
||||
// @lua-preamble -- Roles, not physical buttons: a device maps whatever hardware
|
||||
// it has onto them, and
|
||||
// @lua-preamble -- up/down/left/right are the directions node.moveFocus already
|
||||
// takes.
|
||||
const luaL_Reg INPUT_FUNCTIONS[] = {
|
||||
// ---Returns the roles this device reports, so an app can label only the actions it has.
|
||||
// ---Returns the roles this device reports, so an app can label only the
|
||||
// actions it has.
|
||||
// @return Button[]
|
||||
{"getButtons", getButtons},
|
||||
// ---Whether any button is held.
|
||||
@@ -59,12 +62,14 @@ const luaL_Reg INPUT_FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerButtons(lua_State* state) { augmentGlobal(state, "input", INPUT_FUNCTIONS); }
|
||||
void registerButtons(lua_State* state) {
|
||||
augmentGlobal(state, "input", INPUT_FUNCTIONS);
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
// @lua-global
|
||||
// ---Fired when a button goes down.
|
||||
|
||||
@@ -9,11 +9,13 @@ int setCalibration(lua_State* state) {
|
||||
const int32_t y0 = checkInt(state, 2);
|
||||
const int32_t x1 = checkInt(state, 3);
|
||||
const int32_t y1 = checkInt(state, 4);
|
||||
return pushStatus(state, Runtime::from(state)->touch().setCalibration(x0, y0, x1, y1));
|
||||
return pushStatus(
|
||||
state, Runtime::from(state)->touch().setCalibration(x0, y0, x1, y1));
|
||||
}
|
||||
|
||||
int pushPoint(lua_State* state, bool touched, int32_t x, int32_t y) {
|
||||
if (!touched) return 0;
|
||||
if (!touched)
|
||||
return 0;
|
||||
lua_pushinteger(state, x);
|
||||
lua_pushinteger(state, y);
|
||||
return 2;
|
||||
@@ -53,11 +55,13 @@ const luaL_Reg SETTINGS_FUNCTIONS[] = {
|
||||
|
||||
// @lua-augment input InputLib
|
||||
const luaL_Reg INPUT_FUNCTIONS[] = {
|
||||
// --- Returns the calibrated touch point, or nothing when the panel is not touched.
|
||||
// --- Returns the calibrated touch point, or nothing when the panel is not
|
||||
// touched.
|
||||
// @return integer|nil x
|
||||
// @return integer|nil y
|
||||
{"getTouch", getTouch},
|
||||
// --- Returns the uncalibrated touch reading, or nothing when the panel is not touched.
|
||||
// --- Returns the uncalibrated touch reading, or nothing when the panel is
|
||||
// not touched.
|
||||
// @return integer|nil x
|
||||
// @return integer|nil y
|
||||
{"getRawTouch", getRawTouch},
|
||||
@@ -67,22 +71,23 @@ const luaL_Reg INPUT_FUNCTIONS[] = {
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void registerTouch(lua_State* state) {
|
||||
augmentGlobal(state, "settings", SETTINGS_FUNCTIONS);
|
||||
augmentGlobal(state, "input", INPUT_FUNCTIONS);
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
// @lua-global
|
||||
// ---Fired when the finger lands.
|
||||
// @param x integer
|
||||
// @param y integer
|
||||
// @lua-fn on_touch_down
|
||||
// ---Fired when the finger moves while down, after the firmware's jitter filter.
|
||||
// ---Fired when the finger moves while down, after the firmware's jitter
|
||||
// filter.
|
||||
// @param x integer
|
||||
// @param y integer
|
||||
// @lua-fn on_touch_move
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// Argument and result marshalling shared by the binding sources. Every luaL_check* call
|
||||
// happens before a non-trivial C++ local exists, because a Lua error longjmps past
|
||||
// destructors.
|
||||
// Argument and result marshalling shared by the binding sources. Every
|
||||
// luaL_check* call happens before a non-trivial C++ local exists, because a Lua
|
||||
// error longjmps past destructors.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -29,7 +29,8 @@ inline std::string checkString(lua_State* state, int index) {
|
||||
}
|
||||
|
||||
inline bool optionalString(lua_State* state, int index, std::string& out) {
|
||||
if (lua_isnoneornil(state, index)) return false;
|
||||
if (lua_isnoneornil(state, index))
|
||||
return false;
|
||||
out = checkString(state, index);
|
||||
return true;
|
||||
}
|
||||
@@ -43,12 +44,14 @@ inline int32_t optionalInt(lua_State* state, int index, int32_t fallback) {
|
||||
}
|
||||
|
||||
inline bool optionalColor(lua_State* state, int index, int32_t& out) {
|
||||
if (lua_isnoneornil(state, index)) return false;
|
||||
if (lua_isnoneornil(state, index))
|
||||
return false;
|
||||
out = checkInt(state, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
// `true` on success, `nil, error` on failure: the shape every mutating binding returns.
|
||||
// `true` on success, `nil, error` on failure: the shape every mutating binding
|
||||
// returns.
|
||||
inline int pushStatus(lua_State* state, const Status& status) {
|
||||
if (status.ok) {
|
||||
lua_pushboolean(state, true);
|
||||
@@ -65,7 +68,8 @@ inline int pushError(lua_State* state, const std::string& error) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline void pushStrings(lua_State* state, const std::vector<std::string>& values) {
|
||||
inline void pushStrings(lua_State* state,
|
||||
const std::vector<std::string>& values) {
|
||||
lua_createtable(state, static_cast<int>(values.size()), 0);
|
||||
for (size_t index = 0; index < values.size(); index++) {
|
||||
pushString(state, values[index]);
|
||||
@@ -73,7 +77,8 @@ inline void pushStrings(lua_State* state, const std::vector<std::string>& values
|
||||
}
|
||||
}
|
||||
|
||||
inline void setField(lua_State* state, const char* key, const std::string& value) {
|
||||
inline void setField(lua_State* state, const char* key,
|
||||
const std::string& value) {
|
||||
pushString(state, value);
|
||||
lua_setfield(state, -2, key);
|
||||
}
|
||||
@@ -88,8 +93,10 @@ inline void setField(lua_State* state, const char* key, bool value) {
|
||||
lua_setfield(state, -2, key);
|
||||
}
|
||||
|
||||
// Feature contracts add functions to namespaces the core registrations already created.
|
||||
inline void augmentGlobal(lua_State* state, const char* name, const luaL_Reg* functions) {
|
||||
// Feature contracts add functions to namespaces the core registrations already
|
||||
// created.
|
||||
inline void augmentGlobal(lua_State* state, const char* name,
|
||||
const luaL_Reg* functions) {
|
||||
lua_getglobal(state, name);
|
||||
if (!lua_istable(state, -1)) {
|
||||
lua_pop(state, 1);
|
||||
@@ -101,5 +108,5 @@ inline void augmentGlobal(lua_State* state, const char* name, const luaL_Reg* fu
|
||||
lua_pop(state, 1);
|
||||
}
|
||||
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
} // namespace bindings
|
||||
} // namespace esp32lua
|
||||
|
||||
Reference in New Issue
Block a user