Skip to content

Conversation

@cartok
Copy link

@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 it would be better to define the workspace index, a separator and a position (start, end). This way, one would be able to only display the index (if it's not -1 or manually set -13 or similar). Additionally, it would be possible to get rid of the separator, in case the workspace has only a number and no name.

UPDATE: Better advancement idea is below in a separate comment.

# sway
bindsym Mod4+1 workspace 1:notes # index = 1
bindsym Mod4+8 workspace 8: # index = 8
bindsym Mod4+9 workspace -13: # index = -1  <--- Could also consider allowing negative indices & sorting btw, like 1,2,3,4,-1,-2,-3,-13. But wouldn't want to do that in one go.
bindsym Mod4+0 workspace music # index = -1

# waybar
"sway/workspaces": {
  "format": {
    "pattern": "{name}",
    "index": {
      "show": {
        "positive": true,
        "negative": false
      },
      "pattern": "[{index}]",
      "position": "left",
      "separator": " "
    }
  }
}

results

  • [1] notes
  • [8]
  • ``
  • music
# waybar
"sway/workspaces": {
  "format": {
    "pattern": "{name}",
    "index": {
      "show": {
        "positive": true,
        "negative": false
      },
      "pattern": "{index}",
      "position": "right",
      "separator": " - "
    }
  }
}

results

  • notes - 1
  • 8
  • ``
  • music

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
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