qt: phase 8.2 — [[nodiscard]] on config:: accessors
Mark every config:: read function as [[nodiscard]]. The compiler now catches the silent-drop bug class — calling config::get(&out, "key") without checking the success bit leaves `out` untouched on failure, which means whatever the caller put there earlier is what gets used. Fine when the variable is intentionally pre-initialized to a fallback, crash-prone otherwise. Six call sites genuinely use the default-on-failure pattern; each is made explicit with `(void)config::get(...)` plus a one-liner comment stating that the success bit isn't load-bearing: - quickterm::animationMs (`quick-terminal-animation-duration`) - quickterm::setupLayerShell (`quick-terminal-size`) - MainWindow::newWindow (`initial-window`) - MainWindow::refreshChrome (`quit-after-last-window-closed`) - MainWindow::applyBlur (`background-blur`) - GhosttySurface::paintEvent (`unfocused-split-opacity`) Every other config:: callsite already inspects the return. Co-Authored-By: claude-flow <ruv@ruv.net>pull/12846/head
parent
77deb24fee
commit
a3ad905811
|
|
@ -317,8 +317,10 @@ void GhosttySurface::paintEvent(QPaintEvent *) {
|
|||
// Unfocused-split dimming: a translucent fill over an inactive pane.
|
||||
// Only split panes (a QSplitter parent) are dimmed, matching GTK.
|
||||
if (!hasFocus() && qobject_cast<QSplitter *>(parentWidget())) {
|
||||
double opacity = 0.7;
|
||||
config::get(&opacity, "unfocused-split-opacity");
|
||||
double opacity = 0.7; // default: 70% opaque
|
||||
// On read failure opacity keeps the default; the success bit
|
||||
// isn't load-bearing.
|
||||
(void)config::get(&opacity, "unfocused-split-opacity");
|
||||
if (opacity < 1.0) {
|
||||
QColor fill(0, 0, 0); // default: dim toward black
|
||||
ghostty_config_color_s c{};
|
||||
|
|
|
|||
|
|
@ -289,7 +289,8 @@ MainWindow *MainWindow::newWindow(ghostty_surface_t parent) {
|
|||
if (!s_initialWindowConsumed) {
|
||||
s_initialWindowConsumed = true;
|
||||
bool initialWindow = true;
|
||||
config::get(&initialWindow, "initial-window");
|
||||
// Default-on; the success bit isn't load-bearing.
|
||||
(void)config::get(&initialWindow, "initial-window");
|
||||
wantsShow = initialWindow;
|
||||
}
|
||||
if (wantsShow) w->show();
|
||||
|
|
@ -1068,7 +1069,8 @@ void MainWindow::refreshChrome() {
|
|||
// runtime; mirrors the calculation in initialize().
|
||||
if (GhosttyApp::instance().config()) {
|
||||
bool quitAfter = true;
|
||||
config::get(&quitAfter, "quit-after-last-window-closed");
|
||||
// Default-on; the success bit isn't load-bearing.
|
||||
(void)config::get(&quitAfter, "quit-after-last-window-closed");
|
||||
// Same Duration-decode workaround as initialize().
|
||||
const uint64_t delayNs =
|
||||
config::durationNs("quit-after-last-window-closed-delay", 0);
|
||||
|
|
@ -1370,9 +1372,10 @@ void MainWindow::toggleCommandPalette(GhosttySurface *surface) {
|
|||
void MainWindow::applyBlur() {
|
||||
// background-blur is a union whose C value is an i16: 0 (and the
|
||||
// macOS-only negatives) means off, a positive radius means on. KWin
|
||||
// uses its own configured radius, so only on/off matters here.
|
||||
// uses its own configured radius, so only on/off matters here. On
|
||||
// read failure blur stays 0 (off).
|
||||
short blur = 0;
|
||||
config::get(&blur, "background-blur");
|
||||
(void)config::get(&blur, "background-blur");
|
||||
applyWindowBlur(this, blur > 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,17 +20,17 @@ namespace config {
|
|||
// The live ghostty_config_t. Returns nullptr before the singleton has
|
||||
// finished ensureInitialized — callers that read config during early
|
||||
// startup (before the first MainWindow::initialize) must check.
|
||||
ghostty_config_t handle();
|
||||
[[nodiscard]] ghostty_config_t handle();
|
||||
|
||||
// Read a string-valued config key (or an enum, which libghostty
|
||||
// returns as its tag-name string). Empty if absent or the call
|
||||
// fails.
|
||||
QString string(const char *key);
|
||||
[[nodiscard]] QString string(const char *key);
|
||||
|
||||
// Read a bool-valued config key. Returns `fallback` when the key is
|
||||
// absent or the call fails. Note: libghostty's bool config keys are
|
||||
// strict bools, NOT packed bitfields — see bitfield<>() for those.
|
||||
bool boolean(const char *key, bool fallback);
|
||||
[[nodiscard]] bool boolean(const char *key, bool fallback);
|
||||
|
||||
// Parse a duration config key as nanoseconds via the on-disk
|
||||
// fallback. Use this for `?Duration` (optional) keys: c_get.zig
|
||||
|
|
@ -41,18 +41,18 @@ bool boolean(const char *key, bool fallback);
|
|||
// with `unsigned long long` and a manual ms→ns multiplication, NOT
|
||||
// this wrapper, to avoid a redundant disk re-scan on every read.
|
||||
// Returns `fallbackNs` on parse failure or absent key.
|
||||
uint64_t durationNs(const char *key, uint64_t fallbackNs);
|
||||
[[nodiscard]] uint64_t durationNs(const char *key, uint64_t fallbackNs);
|
||||
|
||||
// Scan the user's primary on-disk config file for `key = value`
|
||||
// directly. Used for keys ghostty_config_get can't decode (Duration,
|
||||
// repeating paths). Returns the last matching value, or empty.
|
||||
QString diskValue(const char *key);
|
||||
[[nodiscard]] QString diskValue(const char *key);
|
||||
|
||||
// True if the live config has any custom-shader entry. Drives
|
||||
// GhosttySurface's premultiply pass — `custom-shader` is a
|
||||
// repeatable path that ghostty_config_get can't expose, so we scan
|
||||
// the on-disk config text directly.
|
||||
bool hasCustomShader();
|
||||
[[nodiscard]] bool hasCustomShader();
|
||||
|
||||
// Read a packed-bitfield config key. libghostty serializes packed
|
||||
// structs as a c_uint via c_get.zig (`ptr.* = @intCast(@as(Backing,
|
||||
|
|
@ -61,14 +61,14 @@ bool hasCustomShader();
|
|||
// for a one-field packed struct) under-sizes the write and corrupts
|
||||
// adjacent stack — always go through this. Returns `fallbackBits`
|
||||
// when ghostty_config_get fails.
|
||||
unsigned int bitfield(const char *key, unsigned int fallbackBits);
|
||||
[[nodiscard]] unsigned int bitfield(const char *key, unsigned int fallbackBits);
|
||||
|
||||
// Read a path-valued disk config and expand a leading `~/` to the
|
||||
// user's home directory. Returns empty when the key is absent.
|
||||
// Path-valued keys are read off-disk (libghostty doesn't surface
|
||||
// them through ghostty_config_get) so this is just diskValue() with
|
||||
// a tilde-expansion pass.
|
||||
QString expandedPath(const char *key);
|
||||
[[nodiscard]] QString expandedPath(const char *key);
|
||||
|
||||
// Wrapper around ghostty_config_get that infers the value's length
|
||||
// from a string literal so call sites stop repeating qstrlen(). The
|
||||
|
|
@ -79,9 +79,11 @@ QString expandedPath(const char *key);
|
|||
// `out` must point to the type ghostty.h documents for the key
|
||||
// (bool* for bool keys, ghostty_config_color_s* for colors, etc.).
|
||||
// Returns false when the key is absent or the underlying call
|
||||
// fails.
|
||||
// fails. The success bit MUST be checked — `out` is left untouched
|
||||
// on failure, so dropping the return masks an unread / unwritten
|
||||
// access.
|
||||
template <typename T, size_t N>
|
||||
inline bool get(T *out, const char (&key)[N]) {
|
||||
[[nodiscard]] inline bool get(T *out, const char (&key)[N]) {
|
||||
static_assert(N > 1, "config::get requires a non-empty key literal");
|
||||
ghostty_config_t cfg = handle();
|
||||
return cfg && ghostty_config_get(cfg, out, key, N - 1);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ constexpr const char *kAnimProperty = "ghastty.quickterm.anim";
|
|||
// and a very large value doesn't lock the user out.
|
||||
int animationMs() {
|
||||
double secs = 0.2; // matches Config.zig default
|
||||
config::get(&secs, "quick-terminal-animation-duration");
|
||||
// On read failure secs keeps the default; the success bit isn't
|
||||
// load-bearing.
|
||||
(void)config::get(&secs, "quick-terminal-animation-duration");
|
||||
if (secs <= 0.0) return 0;
|
||||
return std::clamp(static_cast<int>(secs * 1000.0), 1, 1000);
|
||||
}
|
||||
|
|
@ -117,8 +119,10 @@ void setupLayerShell(QWidget *window) {
|
|||
const QSize scr = screen ? screen->size() : QSize(1920, 1080);
|
||||
|
||||
// quick-terminal-size: primary is the edge-perpendicular extent.
|
||||
// On read failure qsz stays zero-initialized and toPx falls back to
|
||||
// its `fallback` argument; the success bit isn't load-bearing.
|
||||
ghostty_config_quick_terminal_size_s qsz = {};
|
||||
config::get(&qsz, "quick-terminal-size");
|
||||
(void)config::get(&qsz, "quick-terminal-size");
|
||||
const auto toPx = [](const ghostty_quick_terminal_size_s &s, int dim,
|
||||
int fallback) -> int {
|
||||
switch (s.tag) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue