companion icon indicating copy to clipboard operation
companion copied to clipboard

Feature: Number formatting for variables

Open arikorn opened this issue 2 months ago • 9 comments

Is this a feature relevant to companion itself, and not a specific module?

  • [x] I believe this to be a feature for companion, and is not specific to a module

Is there an existing issue for this?

  • [x] I have searched for similiar existing issues

Describe the feature

It would be nice to be able to specify a format for numeric variables.

The simplest one would be to specify the number of decimal places: For example: $(module:SomeNumber:2.1) would specify 2 places before and one place after the decimal (other options: .1 or 0.1 to let left float free; -.1 to add space for negative sign; +.1 to always show + or -)

Fanciest would be full prinft-style formatting

This is similar to #3664, which asked specifically about time variables, but more general (and the "simple" solution may not solve that one.)

Usecases

When changing, for example, audio fader settings in increments of 0.5, with text centered, the number jumps back and forth depending on whether it is round ('1.0') or not ('1.5')

Current behavior:

Image

Here's how it should look (done with an awkward expression that would need to be rewritten for each variable!)

Image

arikorn avatar Oct 10 '25 20:10 arikorn

OK, I see now that the "simplest version", mentioned above, can be done with toFixed() in an expression, but that still requires expressions and a fair bit of skill. So for example (is 4.1 when buttons started supporting expressions for text?):

`mic1:\n${toFixed($(gostream:AudioFader_mic1), 1)}` -- ("Expression Mode") [edit: ] or concat('mic1:\n', toFixed($(gostream:AudioFader_mic1), 1)) -- slightly simpler to write, though longer {end edit]

Instead of: mic1:\n$(gostream:AudioFader_mic1:0.1) -- ("Normal" mode, proposed enhancement)

Still probably worth doing this proposed enhancement -- I had a difficult time getting the expression just right. (Maybe we should add parenthesis matching in expression inputs???)

arikorn avatar Oct 10 '25 22:10 arikorn

Number formatting does need an cleaner way to do it, but I think there could be much cleaner and more intuitive ways to go about it.

For example, while toFixed is somewhat verbose in the need for lots of extra syntax in the whole button string, it's clear what it is and for many it's intuitive as to how it works.

Where as comparatively if one of the ideas is $(gostream:AudioFader_mic1:0.1), for anyone who would see that on a button (such as importing someone else's config, or a multi-operator environment etc...) it's not clear what :0. 1 is at the end of a variable, if that's part of the variable or some modifier for it, it goes against our standard variable formatting of $(SOURCE:NAME) which depending on usage could also be the followed by other syntax for things like indexing a character in a string or getting values out of JSON. Does the period separate :0. 1 into 0 and 1, as separate properties for some sort of functionality? It's not clear or good UX as to what those numbers are or represent.

Personally I'm of the opinion that the $(SOURCE:NAME) syntax for variables should remain untouched, it's what users are familiar with, and any functionality to modify that should be external to the closing paren. For example if we could expand our variable parsing to allow $(SOURCE:NAME).toFixed(1) where when the variable is parsed it also checks if there is a period present followed by a function. If this is done as part of variable parsing it could be supported everywhere that variables are without needing to use Expression and the extra syntax that involves. From a UX point of view at a glance it would be clear that the toFixed function is being used here. This could also grow to more functionality over time in a clear way.

Alternatively, if the primary usage for is would be button text another option could be to have a checkbox in the button styling section that when enabled would automatically perform things like doing toFixed on any numbers that are being parsed in the text, so wouldn't require the user to adjust button text at all, and if they have multiple values such several mics, or different audio channels, all within the same button text they'd all be given the same toFixed.

thedist avatar Oct 10 '25 23:10 thedist

@thedist, I like the idea of a pull-down menu for number formatting (can be more than just fixed-decimals, of course). The only problem is see is if you have different numbers in one string that require different formats...

On my original post, I came across another use-case: in testing repeated actions on the shuttle, I added 0.1 to a variable on the repeating actions. This leads to crazy-long decimal values because of quantization error. In some cases there were so many digits that it couldn't even fit on the button (when using a fixed font-size).

Image

arikorn avatar Oct 11 '25 19:10 arikorn

In thinking about ways to make expressions more manageable / readable (i.e. less nesting of ${} and () and backticks ) it occurred to me that the "natural" way to do it is to use Javascript's flexibility of the + operator.

So rather than:

`mic1:\n${toFixed($(gostream:AudioFader_mic1), 1)}`
or
concat('mic1:\n', toFixed($(gostream:AudioFader_mic1), 1))

one could write:

'mic1:\n' + toFixed($(gostream:AudioFader_mic1),1)

So I submitted a PR (#3699), because it's pretty simple to implement... It's only tangential to this discussion, however. ("Inspired by")

arikorn avatar Oct 12 '25 20:10 arikorn

There are a couple of related ideas floating around (some written down, some not):

  • Allowing expressions to do something like `something: ${vars.gostream.AudioFader_mic1}`, in other words, allowing a less bracket heavy syntax for addressing variables
  • Allowing variables to be structured as more of a tree shape, to allow something like $(gostream:AudioFader:mic1)

So I am also not keen on adding anything else to the variable syntax for this.

My tip for avoiding this becoming too messy is to simply split the expression into more lines, as that usually helps with readability:

level = toFixed($(gostream:AudioFader_mic1), 1)
`mic1:\n${level}`

I am very open to more formatting options, at this point it is simply that noone has asked, and so noone has proposed a plan for it.

Julusian avatar Oct 13 '25 14:10 Julusian

@Julusian wrote:

noone has proposed a plan for it.

hmm... I'd like to think I'm not a "noone"... 😅 but am happy to let this one sit at low priority for now.

I do think that my PR #3699 would be a partial solution and especially make it easier for people trying to compose strings without understanding the vagaries of backticks and ${} operations. It would also simplify "dissecting" expressions that aren't working, and avoid parenthesis mismatches in the first place (without having to resort to the more disciplined multi-statement approach you suggested).

Maybe even, with PR #3699 in place, just adding a printf function like format(x, fmt) using something like fast-printf would be a reasonable (i.e. low-effort) solution?

arikorn avatar Oct 13 '25 19:10 arikorn

I meant that noone before this had proposed anything, so nothing has been done until now.

I think I am open to a printf implementation here. Its not very js-like to do that, but the stdlib of our expressions generally isnt, and it will give the power/flexibility in an easy (to google/chatgpt hopefully) way

Julusian avatar Oct 14 '25 13:10 Julusian

I'm also against adding something to the variable for display formatting. Also I don't see any GUI solution. I second that a formatting function for use in an expression would be the best solution.

As an alternative to printf I could think of an ECMA-376 style formatting function. ECMA-376 defines the formatting syntax used by e.g. Excel or LibreOffice Calc. The benefit is that it can format numbers and dates and it is international and it is better known by the average user. There is a library for it: https://github.com/borgar/numfmt

(BTW you can try it with the dataentry module because I have build the ECMA-376 formatting into it, so actually you can use this module as a generic formatting tool)

dnmeid avatar Nov 12 '25 03:11 dnmeid

@dnmeid, your ECMA-376 suggestion sounds like a good idea.

FWIW, I hadn't been planning on following up personally on this issue, (which is why it has been sitting for a month while I've been contributing to other parts of Companion), so please feel free to do so yourself -- or anyone else reading this post, if Dorian hasn't the time -- it sounds like you have a head start on it already!

arikorn avatar Nov 18 '25 05:11 arikorn