diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-11-22 14:38:52 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-11-22 14:38:52 +1100 |
| commit | 06aca259cbb84c41a002e5a93735b289cc2aa93a (patch) | |
| tree | 3c3a6c09a7362ab95b0019f4bd4da56faf167187 /src | |
| parent | cd46d7bd203b69e6d163fd19e38600d9feae6e56 (diff) | |
| download | tangara-fw-06aca259cbb84c41a002e5a93735b289cc2aa93a.tar.gz | |
Add basic lua browser screen
Diffstat (limited to 'src')
| -rw-r--r-- | src/database/database.cpp | 12 | ||||
| -rw-r--r-- | src/database/include/database.hpp | 1 | ||||
| -rw-r--r-- | src/lua/lua_database.cpp | 77 | ||||
| -rw-r--r-- | src/ui/ui_fsm.cpp | 15 |
4 files changed, 72 insertions, 33 deletions
diff --git a/src/database/database.cpp b/src/database/database.cpp index 88ae7bbe..dad983d0 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -846,8 +846,7 @@ auto IndexRecord::Expand(std::size_t page_size) const if (track_) { return {}; } - IndexKey::Header new_header = ExpandHeader(key_.header, key_.item); - std::string new_prefix = EncodeIndexPrefix(new_header); + std::string new_prefix = EncodeIndexPrefix(ExpandHeader()); return Continuation{ .prefix = {new_prefix.data(), new_prefix.size()}, .start_key = {new_prefix.data(), new_prefix.size()}, @@ -857,6 +856,10 @@ auto IndexRecord::Expand(std::size_t page_size) const }; } +auto IndexRecord::ExpandHeader() const -> IndexKey::Header { + return ::database::ExpandHeader(key_.header, key_.item); +} + Iterator::Iterator(std::weak_ptr<Database> db, const IndexInfo& idx) : db_(db), pos_mutex_(), current_pos_(), prev_pos_() { std::string prefix = EncodeIndexPrefix( @@ -887,6 +890,11 @@ auto Iterator::Next(Callback cb) -> void { db->dbGetPage<IndexRecord>(*current_pos_)}; prev_pos_ = current_pos_; current_pos_ = res->next_page(); + if (!res || res->values().empty() || !res->values()[0]) { + ESP_LOGI(kTag, "dropping empty result"); + InvokeNull(cb); + return; + } std::invoke(cb, *res->values()[0]); }); } diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp index 63014bed..e18701eb 100644 --- a/src/database/include/database.hpp +++ b/src/database/include/database.hpp @@ -80,6 +80,7 @@ class IndexRecord { auto track() const -> std::optional<TrackId>; auto Expand(std::size_t) const -> std::optional<Continuation>; + auto ExpandHeader() const -> IndexKey::Header; private: IndexKey key_; diff --git a/src/lua/lua_database.cpp b/src/lua/lua_database.cpp index d8ae86f6..79916115 100644 --- a/src/lua/lua_database.cpp +++ b/src/lua/lua_database.cpp @@ -20,7 +20,9 @@ #include "event_queue.hpp" #include "index.hpp" #include "property.hpp" +#include "records.hpp" #include "service_locator.hpp" +#include "track.hpp" #include "ui_events.hpp" namespace lua { @@ -55,6 +57,42 @@ static auto indexes(lua_State* state) -> int { static const struct luaL_Reg kDatabaseFuncs[] = {{"indexes", indexes}, {NULL, NULL}}; +/* + * Struct to be used as userdata for the Lua representation of database records. + * In order to push these large values into PSRAM as much as possible, memory + * for these is allocated and managed by Lua. This struct must therefore be + * trivially copyable. + */ +struct LuaRecord { + database::TrackId id_or_zero; + database::IndexKey::Header header_at_next_depth; + size_t text_size; + char text[]; +}; + +static_assert(std::is_trivially_copyable_v<LuaRecord> == true); + +static auto push_lua_record(lua_State* L, const database::IndexRecord& r) + -> void { + // Bake out the text into something concrete. + auto text = r.text().value_or(""); + + // Create and init the userdata. + LuaRecord* record = reinterpret_cast<LuaRecord*>( + lua_newuserdata(L, sizeof(LuaRecord) + text.size())); + luaL_setmetatable(L, kDbRecordMetatable); + + // Init all the fields + *record = { + .id_or_zero = r.track().value_or(0), + .header_at_next_depth = r.ExpandHeader(), + .text_size = text.size(), + }; + + // Copy the string data across. + std::memcpy(record->text, text.data(), text.size()); +} + static auto db_iterate(lua_State* state) -> int { luaL_checktype(state, 1, LUA_TFUNCTION); int callback_ref = luaL_ref(state, LUA_REGISTRYINDEX); @@ -66,11 +104,7 @@ static auto db_iterate(lua_State* state) -> int { events::Ui().RunOnTask([=]() { lua_rawgeti(state, LUA_REGISTRYINDEX, callback_ref); if (res) { - database::IndexRecord** record = - reinterpret_cast<database::IndexRecord**>( - lua_newuserdata(state, sizeof(uintptr_t))); - *record = new database::IndexRecord(*res); - luaL_setmetatable(state, kDbRecordMetatable); + push_lua_record(state, *res); } else { lua_pushnil(state); } @@ -105,40 +139,37 @@ static auto push_iterator( lua_pushcclosure(state, db_iterate, 1); } + static auto record_text(lua_State* state) -> int { - database::IndexRecord* data = *reinterpret_cast<database::IndexRecord**>( + LuaRecord* data = reinterpret_cast<LuaRecord*>( luaL_checkudata(state, 1, kDbRecordMetatable)); - lua_pushstring(state, - data->text().value_or("[tell jacqueline u saw this]").c_str()); + lua_pushlstring(state, data->text, data->text_size); return 1; } static auto record_contents(lua_State* state) -> int { - database::IndexRecord* data = *reinterpret_cast<database::IndexRecord**>( + LuaRecord* data = reinterpret_cast<LuaRecord*>( luaL_checkudata(state, 1, kDbRecordMetatable)); - if (data->track()) { - lua_pushinteger(state, *data->track()); + if (data->id_or_zero) { + lua_pushinteger(state, data->id_or_zero); } else { - push_iterator(state, data->Expand(1).value()); + std::string p = database::EncodeIndexPrefix(data->header_at_next_depth); + push_iterator(state, database::Continuation{ + .prefix = {p.data(), p.size()}, + .start_key = {p.data(), p.size()}, + .forward = true, + .was_prev_forward = true, + .page_size = 1, + }); } return 1; } -static auto record_gc(lua_State* state) -> int { - database::IndexRecord** data = reinterpret_cast<database::IndexRecord**>( - luaL_checkudata(state, 1, kDbRecordMetatable)); - if (data != NULL) { - delete *data; - } - return 0; -} - static const struct luaL_Reg kDbRecordFuncs[] = {{"title", record_text}, {"contents", record_contents}, {"__tostring", record_text}, - {"__gc", record_gc}, {NULL, NULL}}; static auto index_name(lua_State* state) -> int { @@ -207,4 +238,4 @@ auto RegisterDatabaseModule(lua_State* s) -> void { lua_pop(s, 1); } -} // namespace lua
\ No newline at end of file +} // namespace lua diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index d5de53f0..ed0624df 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -219,6 +219,7 @@ void Lua::entry() { {"pop", [&](lua_State* s) { return PopLuaScreen(s); }}, }); + sCurrentScreen.reset(); sLua->RunScript("/lua/main.lua"); } } @@ -243,12 +244,6 @@ auto Lua::PushLuaScreen(lua_State* s) -> int { // Store the reference for the table the constructor returned. new_screen->SetObjRef(s); - // Ensure that we don't pollute the new screen's group. We leave the luavgl - // root alone. - // FIXME: maybe we should set the luavgl root to some catch-all that throws - // when anything is added to it? this may help catch bugs! - lv_group_set_default(NULL); - // Finally, push the now-initialised screen as if it were a regular C++ // screen. PushScreen(new_screen); @@ -256,12 +251,16 @@ auto Lua::PushLuaScreen(lua_State* s) -> int { return 0; } -auto Lua::PopLuaScreen(lua_State*) -> int { +auto Lua::PopLuaScreen(lua_State* s) -> int { PopScreen(); + luavgl_set_root(s, sCurrentScreen->root()); + lv_group_set_default(sCurrentScreen->group()); return 0; } -void Lua::exit() {} +void Lua::exit() { + lv_group_set_default(NULL); +} void Lua::react(const internal::IndexSelected& ev) { auto db = sServices->database().lock(); |
