From f7ca2ab71d9ac0455f3a5e2cd53e13e2697ef58d Mon Sep 17 00:00:00 2001 From: Ekin Dursun Date: Thu, 21 Oct 2021 23:55:33 +0300 Subject: [PATCH] Shorten CWD path For showing the CWD path in a more compact way, this function - shortens path parts before last from right to left, until first character of the path stays (directory -> direc~ or d~) - combines parts before last from right with left (a~/b~ -> a~~) - shortens the last part from middle, preferring to keep characters from left (longdirectoryname -> long~ame) in order (of 2nd and 3rd, the one that removes more characters is applied first) until given maximum length is reached. --- Process.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/Process.c b/Process.c index f0fc67fa69..ae9f300f38 100644 --- a/Process.c +++ b/Process.c @@ -733,6 +733,133 @@ void Process_printPercentage(float val, char* buffer, int n, int* attr) { } } +typedef struct ShortenCwdContext { + char *cwd; + size_t maxLength; + size_t len; + char **parts; + size_t partsLen; + size_t *partLengths; +} ShortenCwdContext; + +static void shortenCwdParts(ShortenCwdContext *ctx) { + for (int i = ctx->partsLen - 2; i >= 0 && ctx->len > ctx->maxLength; i--) { + if (ctx->partLengths[i] < 3) + continue; + + size_t extraChars = ctx->len - ctx->maxLength; + size_t maxRemovableChars = ctx->partLengths[i] - 2; + size_t charsToRemove = extraChars < maxRemovableChars ? extraChars : maxRemovableChars; + + ctx->partLengths[i] -= charsToRemove; + ctx->len -= charsToRemove; + String_safeStrncpy(ctx->parts[i] + (ctx->partLengths[i] - 1), "~", 2); + } +} + +static size_t collapseCwdParts(ShortenCwdContext *ctx, bool doActualWork) { + if (ctx->len <= ctx->maxLength || ctx->partsLen <= 3) + return 0; + + size_t len = ctx->len; + + size_t i; + for (i = ctx->partsLen - 2; i > 1; i--) { + if (len + (3 - ctx->partLengths[i]) <= ctx->maxLength) + break; + + len -= ctx->partLengths[i] + 1; + + if (doActualWork) { + ctx->partLengths[i] = 0; + free(ctx->parts[i]); + ctx->parts[i] = NULL; + } + } + + len += 3 - ctx->partLengths[i]; + size_t diff = ctx->len - len; + + if (doActualWork) { + char newPart[] = "~~~"; + newPart[0] = ctx->parts[i][0]; + free_and_xStrdup(&ctx->parts[i], newPart); + ctx->partLengths[i] = 3; + ctx->len = len; + } + + return diff; +} + +static size_t shortenCwdLastPart(ShortenCwdContext *ctx, bool doActualWork) { + if (ctx->len <= ctx->maxLength) + return 0; + + size_t lastPartLen = ctx->partLengths[ctx->partsLen - 1]; + if (lastPartLen <= 3) + return 0; + + char *lastPart = ctx->parts[ctx->partsLen - 1]; + size_t extraChars = ctx->len - ctx->maxLength + 1; + size_t maxRemovableChars = lastPartLen - 2; + size_t charsToRemove = extraChars < maxRemovableChars ? extraChars : maxRemovableChars; + + if (doActualWork) { + size_t charsAtBeginning = (lastPartLen - charsToRemove + 1) / 2; + size_t charsAtEnd = lastPartLen - charsToRemove - charsAtBeginning; + lastPart[charsAtBeginning] = '~'; + memmove(lastPart + charsAtBeginning + 1, lastPart + lastPartLen - charsAtEnd, charsAtEnd); + lastPart[charsAtBeginning + charsAtEnd + 1] = '\0'; + ctx->partLengths[ctx->partsLen - 1] = lastPartLen - charsToRemove + 1; + ctx->len -= charsToRemove - 1; + } + + return charsToRemove - 1; +} + +static void writeCwdUsingParts(ShortenCwdContext *ctx) { + ctx->cwd[0] = '\0'; + for (size_t i = 0, writeIndex = 0; i < ctx->partsLen; i++) { + if (!ctx->parts[i]) + continue; + + String_safeStrncpy(ctx->cwd + writeIndex, ctx->parts[i], ctx->partLengths[i] + 1); + writeIndex += ctx->partLengths[i]; + if (i < ctx->partsLen - 1) + ctx->cwd[writeIndex++] = '/'; + } +} + +static void shortenCwd(char *cwd, const size_t maxLength) { + size_t len = strlen(cwd); + if (len <= maxLength) + return; + + ShortenCwdContext ctx = { + .cwd = cwd, + .maxLength = maxLength, + .len = len, + }; + ctx.parts = String_split(cwd, '/', &ctx.partsLen); + ctx.partLengths = xCalloc(ctx.partsLen, sizeof(size_t)); + for (size_t i = 0; i < ctx.partsLen; i++) + ctx.partLengths[i] = strlen(ctx.parts[i]); + + shortenCwdParts(&ctx); + if (shortenCwdLastPart(&ctx, false) > collapseCwdParts(&ctx, false)) { + shortenCwdLastPart(&ctx, true); + collapseCwdParts(&ctx, true); + } else { + collapseCwdParts(&ctx, true); + shortenCwdLastPart(&ctx, true); + } + + writeCwdUsingParts(&ctx); + + free(ctx.partLengths); + String_freeArray(ctx.parts); +} + void Process_writeField(const Process* this, RichString* str, ProcessField field) { char buffer[256]; size_t n = sizeof(buffer); @@ -825,6 +952,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field attr = CRT_colors[PROCESS_SHADOW]; cwd = "main thread terminated"; } else { + shortenCwd(this->procCwd, 25); cwd = this->procCwd; } Process_printLeftAlignedField(str, attr, cwd, 25);