polybar
polybar copied to clipboard
Escape Tokens in labels
Currently, module tokens are being parsed inside action tags. I believe this is a bug.
Example with MPD
When I click on label-song
, I want to be sent a notification with information about what's currently playing via mpc
. In this example, I am send a notication with the name of the current album playing:
[module/mpd-nowplaying]
label-song = %{A1:notify-send "Currently Playing" "$(mpc -f "%album%" | head -1)":%album% - %title%%{A}
However, this config will interpret %album%
and treat it like an mpd
toke, expanding it to the name of the currently playing album:
notify-send "Currently Playing" "$(mpc -f "<currently playing album>" | head -1)"
For this specific usecase, you may think well what's the problem? Either polybar or mpc will end up expanding %album%
to the album anyways, so it doesn't matter?
However, if the album contains a colon (:
), it will not be escaped, and so the command will look like this:
notify-send "Currently Playing" "$(mpc -f "Example Album: Super Collection" | head -1)"
This leads to errors like this:
error: Failed to parse contents (reason: Unrecognized token 'S')
error: Failed to parse contents (reason: Unrecognized token 'S')
error: Failed to parse contents (reason: Unrecognized token 'S')
error: Failed to parse contents (reason: Unrecognized token 'S')
error: Failed to parse contents (reason: Unrecognized token 'S')
error: Failed to parse contents (reason: Unrecognized token 'S')
error: Failed to parse contents (reason: Unrecognized token 'S')
error: Failed to parse contents (reason: Unrecognized token 'S')
...
Long story short, tokens that have the potential to contain colons are particularly dangerous and should not be parsed/expanded.
Trying to Escape the Token
If you escape the token with backslashes, the token is not interpreted, but the backslashes are not removed when sent to the shell, so the command will look like:
notify-send "Currently Playing" "$(mpc -f "\%album\%" | head -1)"
Since it is still escaped, mpc
will not recognize it as a format tag.
Solutions
- Don't parse tokens inside action tags.
- Allow tokens like
%album%
to be escaped, like\%album\%
, and remove the backslashes when parsing, similarly to how escaped colons' backslashes are deleted before the command is sent to the shell (e.g.\:
becomes:
, then is sent to shell).
Version Info
Output of polybar -vvv
:
polybar 3.4.0-80-gc9a43dd
Features: +alsa +curl +i3 +mpd +network(libnl) +pulseaudio +xkeyboard
X extensions: +randr (+monitors) +composite +xkb +xrm +xcursor
Build type: Release
Compiler: /usr/bin/c++
Compiler flags: -Wall -Wextra -Wpedantic -O3 -DNDEBUG
Linker flags:
I have noticed a possible earlier response in #2063:
a polybar token is placed inside a user-defined action tag and polybar doesn't know it needs to escape the colons and we will indeed not fix this. -- @patrick96
So, it is possible this is a duplicate of #887 and the answer may already be no. However, in that specific use case, there was a workaround because of the specific command being used, which is not possible here. I am keeping this open to see the response.
Even if the answer is "not right now," I don't think that's a good reason to close this, as it is an important fix.
It seems that this is part of a larger parsing problem with more than just colons. There have also been problems escaping {
/}
characters (#2040, #2061, #2063).
It seems an approach was started in #1065.
I have found a workaround to escape tokens inside action tags: by surrounding each %
with double quotes, parsing is prevented. For example:
label-song = %{A1:notify-send "Currently Playing" "$(mpc -f "%""artist""%\: ""%""album""%"" - ""%""title""%" | head -1)":}%{u#C0C5C5}%{+u}%album:0:32:…%%{-u} - %title%%{A}
This way, each character is still sent correctly to the shell, and the tokens are not parsed. It's a bit unreadable, and it just a workaround, but it does work.
This is indeed the same issue as #887 and the answer there is still that it is not possible (or at least not feasible), though my proposal in https://github.com/polybar/polybar/issues/1524 may give an alternative where you could use tokens. The other issues you linked are not related to this.
The solution here is to let users escape tokens.
EDIT:
For anyone wanting to tackle this, this requires the label code in label.cpp
recognizing escaped percentage signs (\%
). When producing output, it needs to produce only percentage signs for the escaped percentage sign and when replacing tokens it needs to ignore labels that have escaped percentage signs.
The load_label
function also needs to be adapted to only gather tokens without escaped percentage signs.