From 102ddbc64b9b7b435a862759f7164710a2a49ed9 Mon Sep 17 00:00:00 2001 From: janb84 Date: Thu, 14 May 2026 11:19:46 +0200 Subject: [PATCH 1/3] feat: change feerate diagram with autowidth --- lua/examples/feeratediagram.lua | 12 +++++++- src/tabs/luatab.cpp | 49 +++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/lua/examples/feeratediagram.lua b/lua/examples/feeratediagram.lua index 696f184..d749c4e 100644 --- a/lua/examples/feeratediagram.lua +++ b/lua/examples/feeratediagram.lua @@ -9,8 +9,10 @@ btcui_set_name("Feerate") local REFRESH = tonumber(btcui_option("refresh", 5)) -local PLOT_WIDTH = tonumber(btcui_option("width", 80)) +-- width=0 (default) auto-scales to the terminal width; any positive value pins it. +local FIXED_WIDTH = tonumber(btcui_option("width", 0)) local PLOT_HEIGHT = tonumber(btcui_option("height", 14)) +local PLOT_WIDTH = FIXED_WIDTH > 0 and FIXED_WIDTH or 80 local BLOCK_WU = 4000000 -- 4 MWU = one block ---------------------------------------------------------------------- @@ -151,6 +153,14 @@ end local warned_no_rpc = false local function refresh() + -- Resize the plot to fill the terminal width unless the user pinned it. + -- Subtract the panel border (2), the table column's left-gutter (1), and + -- the Y-axis label area (AXIS_PAD). + if FIXED_WIDTH <= 0 then + local sw = btcui_screen_size() + PLOT_WIDTH = math.max(20, sw - AXIS_PAD - 3) + end + local info = btcui_rpc("getmempoolinfo") if info then mempool_summary:set({ diff --git a/src/tabs/luatab.cpp b/src/tabs/luatab.cpp index c230e27..b92825f 100644 --- a/src/tabs/luatab.cpp +++ b/src/tabs/luatab.cpp @@ -24,17 +24,37 @@ using Clock = std::chrono::system_clock; using TimePoint = Clock::time_point; static const std::set DEFAULT_RPC_ALLOWLIST = { - "decoderawtransaction", "decodescript", "estimatesmartfee", - "getbestblockhash", "getblock", "getblockchaininfo", - "getblockcount", "getblockhash", "getblockheader", - "getblockstats", "getchaintips", "getconnectioncount", - "getdeploymentinfo", "getindexinfo", "getmempoolancestors", - "getmempoolcluster", "getmempooldescendants", - "getmempoolentry", "getmempoolfeeratediagram", - "getmempoolinfo", "getmininginfo", "getnettotals", - "getnetworkhashps", "getnetworkinfo", "getnodeaddresses", - "getpeerinfo", "getrawmempool", "getrawtransaction", - "gettxout", "gettxoutsetinfo", "logging", + "decoderawtransaction", + "decodescript", + "estimatesmartfee", + "getbestblockhash", + "getblock", + "getblockchaininfo", + "getblockcount", + "getblockhash", + "getblockheader", + "getblockstats", + "getchaintips", + "getconnectioncount", + "getdeploymentinfo", + "getindexinfo", + "getmempoolancestors", + "getmempoolcluster", + "getmempooldescendants", + "getmempoolentry", + "getmempoolfeeratediagram", + "getmempoolinfo", + "getmininginfo", + "getnettotals", + "getnetworkhashps", + "getnetworkinfo", + "getnodeaddresses", + "getpeerinfo", + "getrawmempool", + "getrawtransaction", + "gettxout", + "gettxoutsetinfo", + "logging", "uptime", }; @@ -465,6 +485,13 @@ void LuaTab::register_lua_api(LuaScript& script) { lua_tab_state_.update([&](auto& st) { st.tab_name = name; }); }; + lua_["btcui_screen_size"] = [this](sol::this_state ts) -> sol::variadic_results { + sol::variadic_results vr; + vr.push_back({ts, sol::in_place, screen_.dimx()}); + vr.push_back({ts, sol::in_place, screen_.dimy()}); + return vr; + }; + lua_["btcui_option"] = [this](sol::this_state ts, const std::string& key, sol::optional default_val) -> sol::object { if (tab_options_.contains(key)) From 64c41b12b6544ce2580f8307cc2b7fa089b096bf Mon Sep 17 00:00:00 2001 From: janb84 Date: Thu, 14 May 2026 11:20:07 +0200 Subject: [PATCH 2/3] feat: update changelog with new Lua features and Windows support --- CHANGELOG.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5fa9b4..0f4b7e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ All notable changes to bitcoin-tui are documented here. ### Added - **Mouse support** - click tabs to switch between them - **Clickable footer bar** - footer hints are now rendered as a dedicated mouse-aware footer bar; click refresh/search/quit and tab-specific actions directly -- **Lua scripting** - load custom tabs from Lua scripts with `--tab `; scripts can call a configurable set of RPC methods (allowlisted with `--allow-rpc`); optional debug log via `--debuglog`; bundled example: slow-block monitor tab +- **Lua scripting** - load custom tabs from Lua scripts with `--tab `; scripts can call a configurable set of RPC methods (allowlisted with `--allow-rpc`); optional debug log via `--debuglog`; bundled examples: slow-block monitor, wallet info, feerate diagram - **Lua footer buttons** - Lua scripts can register clickable footer actions with `btcui_add_footer_button(label, callback)`; `btcui_show_search_button(bool)` and `btcui_show_quit_button(bool)` let scripts hide the global search and quit buttons per-tab - **Config file support** - options can be set in a `config.toml` file (Linux: `$XDG_CONFIG_HOME/bitcoin-tui/` or `~/.config/bitcoin-tui/`; macOS: `~/Library/Application Support/bitcoin-tui/`; Windows: `%APPDATA%\bitcoin-tui\`); CLI flags override file values; path can be changed with `--config` - - CLI11 replaces hand-rolled argument parsing; adds `--help` grouping, `--config` file support, and stricter validation of unknown flags @@ -15,10 +15,21 @@ All notable changes to bitcoin-tui are documented here. - **Lua footer button keyboard shortcuts** - `btcui_add_footer_button` now auto-extracts the keyboard shortcut from `[x]` patterns in the label (e.g. `"[r] QR"` binds the `r` key automatically); an explicit key can also be passed as the optional third argument - **QR code overlay** - `btcui_open_qr_overlay(data)` opens a full-screen QR overlay; accepts a plain address string or a list of `{label, data}` items for a tabbed overlay; `left arrow/ right arrow` arrow keys switch between tabs; - **Lua table row selection** - users can select a row in any Lua table panel by pressing `arrow down` to focus the panel, `Enter` to enter selection mode, `arrow up / arrow down` to move the selection, and `Esc` to exit selection mode; selected row is highlighted; `Table:selected_key()` returns the key of the selected row and `Table:selected_value(column)` returns the formatted value of any column in that row, enabling Lua callbacks to act on the user's selection +- **testnet4 support** - `--testnet4` shortcut for connecting to the testnet4 network +- **Windows support** - native MSVC build target with bundled application icon, automatic detection of the default Windows bitcoin data directory, and a dedicated console window when launched from Explorer +- **Lua scrollable tables** - large Lua tables can now be scrolled when they exceed the available panel height +- **Lua summary panels** - Lua scripts can render compact key/value summary panels alongside tables +- **Lua untitled panels** - panels in Lua tabs can omit a title for a cleaner layout +- **Lua address element** - styled address rendering element exposed to the Lua API +- **Lua wallet RPC selection** - `btcui_rpc_wallet(name)` directs subsequent RPC calls at a specific named wallet +- **Lua script options** - `btcui_option(name)` reads CLI/config-file values passed through to scripts +- **Lua timestamp formats** - multiple timestamp formats now exposed to Lua scripts ### Changed - FTXUI updated from v5.0.0 to v6.1.9 - Footer hints are unified across tabs: context-sensitive actions now appear in one shared footer bar instead of each tab rendering its own status text +- FetchContent dependencies are now pinned by SHA256 hash for reproducibility + ## [0.8.3] - 2026-04-11 From 39a6572f4641727b58688e6aab79ee058673caa6 Mon Sep 17 00:00:00 2001 From: janb84 Date: Thu, 14 May 2026 11:36:51 +0200 Subject: [PATCH 3/3] feat: added callback on_resize() --- lua/api.lua | 20 ++++++++++++++++++++ lua/examples/feeratediagram.lua | 6 ++++++ src/tabs/luatab.cpp | 27 ++++++++++++++++++++++++++- src/tabs/luatab.hpp | 3 +++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lua/api.lua b/lua/api.lua index 9638b6d..6c5a35b 100644 --- a/lua/api.lua +++ b/lua/api.lua @@ -138,6 +138,26 @@ function btcui_show_search_button(show) end ---@param show boolean function btcui_show_quit_button(show) end +--- Return the current terminal dimensions in cells (width, height). +--- The value reflects the most recent render and updates as the user +--- resizes the terminal. Useful for sizing plots or laying out +--- variable-width content. Pair with btcui_on_resize() to react to +--- changes immediately instead of on the next refresh tick. +---@return integer width +---@return integer height +function btcui_screen_size() end + +--- Register a callback that fires whenever the terminal is resized. +--- The callback receives the new (width, height). Only one handler +--- can be registered — a second call replaces the previous one. +--- A common pattern is to wake a refresh timer: +--- +--- local timer = btcui_set_interval(5, refresh) +--- btcui_on_resize(function(w, h) btcui_wake(timer) end) +--- +---@param callback fun(width: integer, height: integer) +function btcui_on_resize(callback) end + --- Return a styled address cell value. The address is rendered with --- alternating bold groups of 4 characters (e.g. "bc1q ar0s rr7x …"), --- making it easier to scan visually. Pass the result as a cell value diff --git a/lua/examples/feeratediagram.lua b/lua/examples/feeratediagram.lua index d749c4e..58d5600 100644 --- a/lua/examples/feeratediagram.lua +++ b/lua/examples/feeratediagram.lua @@ -304,3 +304,9 @@ end local timer = btcui_set_interval(REFRESH, refresh) btcui_add_footer_button(" ↺ refresh", function() btcui_wake(timer) end) + +-- Re-run refresh() immediately when the terminal is resized so the plot +-- adapts to the new width without waiting for the next periodic tick. +if FIXED_WIDTH <= 0 then + btcui_on_resize(function() btcui_wake(timer) end) +end diff --git a/src/tabs/luatab.cpp b/src/tabs/luatab.cpp index b92825f..bd02fdf 100644 --- a/src/tabs/luatab.cpp +++ b/src/tabs/luatab.cpp @@ -157,7 +157,9 @@ class LuaScript { } public: - std::ostream* debug_out = nullptr; + std::ostream* debug_out = nullptr; + sol::protected_function on_resize_fn_; + std::string on_resize_src_; private: sol::state lua_; @@ -492,6 +494,11 @@ void LuaTab::register_lua_api(LuaScript& script) { return vr; }; + lua_["btcui_on_resize"] = [&script](sol::protected_function fn) { + script.on_resize_src_ = lua_source_id(fn.lua_state()); + script.on_resize_fn_ = std::move(fn); + }; + lua_["btcui_option"] = [this](sol::this_state ts, const std::string& key, sol::optional default_val) -> sol::object { if (tab_options_.contains(key)) @@ -695,6 +702,17 @@ void LuaTab::lua_thread_fn(std::unique_ptr script) { } } + // 0b. Fire resize callback if the UI reported a size change + if (resize_pending_.exchange(false) && script->on_resize_fn_.valid()) { + auto result = script->on_resize_fn_(screen_.dimx(), screen_.dimy()); + if (!result.valid()) { + sol::error err = result; + report_callback_error(-1, script->on_resize_src_, err.what()); + } else { + clear_callback_error(-1); + } + } + // 1. Read new log lines, feed to Lua callbacks if (logfile) { while (std::getline(logfile, line)) { @@ -1122,6 +1140,13 @@ static Element render_cell_element(const std::string& prefix, const CellValue& c } Element LuaTab::render(const AppState& /*snap*/) { + int dx = screen_.dimx(); + int dy = screen_.dimy(); + int prev_x = last_dimx_.exchange(dx); + int prev_y = last_dimy_.exchange(dy); + if ((prev_x != 0 || prev_y != 0) && (prev_x != dx || prev_y != dy)) + resize_pending_.store(true); + struct PanelInfo { Elements chrome; // title, header+separator (rendered before data rows) Elements data_rows; // scrollable content diff --git a/src/tabs/luatab.hpp b/src/tabs/luatab.hpp index 69d08c5..2bc8e51 100644 --- a/src/tabs/luatab.hpp +++ b/src/tabs/luatab.hpp @@ -90,5 +90,8 @@ class LuaTab : public Tab { std::atomic focused_panel_{-1}; std::atomic panel_scrolling_{false}; mutable Guarded> btn_click_queue_; + std::atomic resize_pending_{false}; + std::atomic last_dimx_{0}; + std::atomic last_dimy_{0}; std::thread lua_thread_; };