Skip to content

feat(sway/workspaces): add format for negative indices#4747

Open
cartok wants to merge 1 commit intoAlexays:masterfrom
cartok:feat/sway-workspaces-format-for-negative-indices
Open

feat(sway/workspaces): add format for negative indices#4747
cartok wants to merge 1 commit intoAlexays:masterfrom
cartok:feat/sway-workspaces-format-for-negative-indices

Conversation

@cartok
Copy link
Contributor

@cartok cartok commented Dec 31, 2025

Hi Alexis,

Would this be fine for you?
Any adjustments?

I didn't want to break the former flexibility, but actually think that this solution in this MR isn't flexible enough, cause it can't deal with empty values well. In the next comment is a generally applicable alternative format solution idea.

Happy New Year!

@cartok cartok force-pushed the feat/sway-workspaces-format-for-negative-indices branch from 56d5597 to 9e53174 Compare January 1, 2026 01:43
@cartok
Copy link
Contributor Author

cartok commented Jan 2, 2026

Better Advancement Idea

There could be an advanced format which is defined as an array of objects instead of a standard template string. Therefore, JitCat would most likely be the best tool. C++ code is sketched by AI.

  1. JSON Configuration
{
  "format": [
    {
      "kind": "var",
      "name": "index",
      "render": "[{index}]",
      "condition": "index > 0"
    },
    {
      "kind": "text",
      "value": " | ",
      "condition": "index > 0"
    },
    {
      "kind": "var",
      "name": "name",
      "condition": "name.length() > 0"
    },
    {
      "kind": "text",
      "value": " on ",
      "condition": "name.length() > 0 && output.length() > 0"
    },
    {
      "kind": "var",
      "name": "output",
      "condition": "output.length() > 0"
    }
  ]
}
  1. Runtime Context
#include <string>
#include <unordered_map>
#include <variant>

using Value = std::variant<int, double, std::string, bool>;

struct Context {
    std::unordered_map<std::string, Value> vars;

    int getInt(const std::string& name) const {
        auto it = vars.find(name);
        if (it != vars.end() && std::holds_alternative<int>(it->second))
            return std::get<int>(it->second);
        return 0;
    }

    double getDouble(const std::string& name) const {
        auto it = vars.find(name);
        if (it != vars.end() && std::holds_alternative<double>(it->second))
            return std::get<double>(it->second);
        return 0.0;
    }

    std::string getString(const std::string& name) const {
        auto it = vars.find(name);
        if (it != vars.end() && std::holds_alternative<std::string>(it->second))
            return std::get<std::string>(it->second);
        return "";
    }
};
  1. Reflection for JitCat
#include <jitcat/Reflection.h>

JITCAT_REFLECT(Context,
    JITCAT_METHOD(getInt),
    JITCAT_METHOD(getDouble),
    JITCAT_METHOD(getString)
)
  1. Rendering
#include <jitcat/Expression.h>
#include <fmt/core.h>
#include <nlohmann/json.hpp> // optional, for parsing JSON

std::string render(const nlohmann::json& formatArray, Context& ctx) {
    std::string output;

    for (const auto& node : formatArray) {
        std::string condition = node.value("condition", "true");

        // Build JitCat expression
        jitcat::Expression<bool> expr(condition);

        if (!expr.evaluate(&ctx))
            continue; // skip node if condition false

        if (node["kind"] == "text") {
            output += node["value"].get<std::string>();
        } 
        else if (node["kind"] == "var") {
            std::string name = node["name"].get<std::string>();
            std::string renderTemplate = node.value("render", "{" + name + "}");

            // Simple replacement for {var} in template
            std::string value;
            if (ctx.vars.find(name) != ctx.vars.end()) {
                const auto& v = ctx.vars.at(name);
                if (std::holds_alternative<int>(v))
                    value = fmt::format("{}", std::get<int>(v));
                else if (std::holds_alternative<double>(v))
                    value = fmt::format("{}", std::get<double>(v));
                else if (std::holds_alternative<std::string>(v))
                    value = std::get<std::string>(v);
                else if (std::holds_alternative<bool>(v))
                    value = std::get<bool>(v) ? "true" : "false";
            }

            // Replace {var} placeholder in renderTemplate
            size_t pos = renderTemplate.find("{" + name + "}");
            if (pos != std::string::npos)
                renderTemplate.replace(pos, name.size() + 2, value);

            output += renderTemplate;
        }
    }

    return output;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant