diff --git a/doc/help.json b/doc/help.json index 1d882d133..d320a3674 100644 --- a/doc/help.json +++ b/doc/help.json @@ -291,12 +291,17 @@ } }, { - "long": "logo-recache", - "desc": "If true, regenerate the image logo cache", + "long": "logo-cache", + "desc": "Specify how the image logo cache is used", "arg": { - "type": "bool", + "type": "enum", "optional": true, - "default": false + "default": "true", + "enum": { + "true": "Reuse a cached rendering when it is valid, and write it back on a cache miss", + "false": "Ignore the image logo cache completely: neither read nor write it", + "regen": "Ignore any existing cached rendering and regenerate it" + } } }, { diff --git a/doc/json_schema.json b/doc/json_schema.json index cfa85ea4c..aa472e6af 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -766,10 +766,19 @@ "description": "Whether to preserve the aspect ratio of the logo. Supported by iTerm image protocol only", "default": false }, - "recache": { - "type": "boolean", - "description": "If true, regenerate image logo cache", - "default": false + "cache": { + "description": "How the image logo cache is used. true reuses a cached rendering when it is valid and writes it back on a cache miss; false ignores the cache completely, neither reading nor writing it; \"regen\" ignores any existing cached rendering and regenerates it", + "oneOf": [ + { + "type": "boolean", + "description": "Whether to use the image logo cache" + }, + { + "const": "regen", + "description": "Regenerate the image logo cache, ignoring any existing cached rendering" + } + ], + "default": true }, "position": { "type": "string", diff --git a/src/logo/image/image.c b/src/logo/image/image.c index 514a0bc88..b9e39c7b7 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -405,6 +405,12 @@ static bool compressBlob(void** blob, size_t* length) { #endif // FF_HAVE_ZLIB static void writeCacheData(FFLogoRequestData* requestData, const void* value, size_t len, const char* cacheFileName) { + // Every payload file goes through here, including the ones written from the printing helpers, + // so this is the single place that keeps `--logo-cache false` from writing anything at all. + if (instance.config.logo.cache == FF_LOGO_CACHE_OFF) { + return; + } + uint32_t cacheDirLength = requestData->cacheDir.length; ffStrbufAppendS(&requestData->cacheDir, cacheFileName); ffWriteFileData(requestData->cacheDir.chars, len, value); @@ -905,7 +911,7 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError) { // 0 means the mtime could not be read, in which case the entry is never trusted. const uint64_t sourceMtime = ffPathGetMtime(instance.config.logo.source.chars); - if (!instance.config.logo.recache && + if (instance.config.logo.cache == FF_LOGO_CACHE_ON && sourceMtime != 0 && readCachedUint64(&requestData, FF_CACHE_FILE_MTIME) == sourceMtime) { bool cacheValid = requestData.type == FF_LOGO_TYPE_IMAGE_CHAFA @@ -919,7 +925,10 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError) { // Cache miss. The entry directory is keyed on the source path and the pixel size only, so // it is reused when the source is edited; drop what the previous version left behind. - removeCachedFiles(&requestData); + // With the cache turned off the directory is left alone entirely. + if (instance.config.logo.cache != FF_LOGO_CACHE_OFF) { + removeCachedFiles(&requestData); + } const char* error = nullptr; bool printSuccessful = false; diff --git a/src/options/logo.c b/src/options/logo.c index e62bd23b7..08a35cc45 100644 --- a/src/options/logo.c +++ b/src/options/logo.c @@ -17,7 +17,7 @@ void ffOptionsInitLogo(FFOptionsLogo* options) { options->paddingRight = 4; options->printRemaining = true; options->preserveAspectRatio = false; - options->recache = false; + options->cache = FF_LOGO_CACHE_ON; options->position = FF_LOGO_POSITION_LEFT; #if FF_HAVE_CHAFA @@ -105,8 +105,15 @@ bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, cons options->printRemaining = ffOptionParseBoolean(value); } else if (ffStrEqualsIgnCase(subKey, "preserve-aspect-ratio")) { options->preserveAspectRatio = ffOptionParseBoolean(value); + } else if (ffStrEqualsIgnCase(subKey, "cache")) { + if (value && ffStrEqualsIgnCase(value, "regen")) { + options->cache = FF_LOGO_CACHE_REGEN; + } else { + options->cache = ffOptionParseBoolean(value) ? FF_LOGO_CACHE_ON : FF_LOGO_CACHE_OFF; + } } else if (ffStrEqualsIgnCase(subKey, "recache")) { - options->recache = ffOptionParseBoolean(value); + fputs("--logo-recache has been replaced by --logo-cache regen\n", stderr); + exit(477); } else if (ffStrEqualsIgnCase(subKey, "separate")) { fputs("--logo-separate has been renamed to --logo-position\n", stderr); exit(477); @@ -335,8 +342,14 @@ const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* roo } else if (unsafe_yyjson_equals_str(key, "preserveAspectRatio")) { options->preserveAspectRatio = yyjson_get_bool(val); continue; - } else if (unsafe_yyjson_equals_str(key, "recache")) { - options->recache = yyjson_get_bool(val); + } else if (unsafe_yyjson_equals_str(key, "cache")) { + if (yyjson_is_bool(val)) { + options->cache = yyjson_get_bool(val) ? FF_LOGO_CACHE_ON : FF_LOGO_CACHE_OFF; + } else if (yyjson_is_str(val) && ffStrEqualsIgnCase(yyjson_get_str(val), "regen")) { + options->cache = FF_LOGO_CACHE_REGEN; + } else { + return "Property 'logo.cache' must be a boolean or the string \"regen\""; + } continue; } else if (unsafe_yyjson_equals_str(key, "position")) { int value; @@ -521,7 +534,18 @@ void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options) { yyjson_mut_obj_add_bool(doc, obj, "preserveAspectRatio", options->preserveAspectRatio); - yyjson_mut_obj_add_bool(doc, obj, "recache", options->recache); + // Written the way the parser accepts it back: a boolean for on / off, the string for regen + switch (options->cache) { + case FF_LOGO_CACHE_OFF: + yyjson_mut_obj_add_bool(doc, obj, "cache", false); + break; + case FF_LOGO_CACHE_REGEN: + yyjson_mut_obj_add_str(doc, obj, "cache", "regen"); + break; + case FF_LOGO_CACHE_ON: + yyjson_mut_obj_add_bool(doc, obj, "cache", true); + break; + } yyjson_mut_obj_add_str(doc, obj, "position", ((const char*[]) { "left", diff --git a/src/options/logo.h b/src/options/logo.h index 51d5cfbfc..c6e1eb9f6 100644 --- a/src/options/logo.h +++ b/src/options/logo.h @@ -30,6 +30,12 @@ typedef enum FFLogoPosition: uint8_t { FF_LOGO_POSITION_RIGHT, } FFLogoPosition; +typedef enum FFLogoCacheStrategy: uint8_t { + FF_LOGO_CACHE_ON, // reuse a cached rendering when it is valid, and write it back on a cache miss + FF_LOGO_CACHE_OFF, // ignore the image logo cache completely: neither read nor write it + FF_LOGO_CACHE_REGEN, // ignore any existing cached rendering and regenerate it +} FFLogoCacheStrategy; + typedef struct FFOptionsLogo { FFstrbuf source; FFLogoType type; @@ -43,7 +49,7 @@ typedef struct FFOptionsLogo { uint32_t paddingBottom; bool printRemaining; bool preserveAspectRatio; - bool recache; + FFLogoCacheStrategy cache; #if FF_HAVE_CHAFA bool chafaFgOnly;