It is currently October 22nd, 2024, 6:49 pm

[BUG] Multiple Lua functions calling CURRENTSECTION

Report bugs with the Rainmeter application and suggest features.
User avatar
Yincognito
Rainmeter Sage
Posts: 8534
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

[BUG] Multiple Lua functions calling CURRENTSECTION

Post by Yincognito »

I believe this might be a test case that we missed when Brian was kind enough to provide the ability to retrieve the value of CURRENTSECTION from Lua some time ago, or otherwise a very curious syntactical / parsing bug...

[SkinFolder]\@Resources\S.lua:

Code: Select all

-- Returns the string result of the formula (arg[3]) for the desired occurrence (arg[2]) of an index from the desired section (arg[1]) 
function SectionIndex(...)
  local Indexes = {}
  for index in (arg[1] or SKIN:GetVariable('CURRENTSECTION')):gmatch('%d+') do
    Indexes[#indexes + 1] = index
  end
  return tostring(SKIN:ParseFormula((arg[3] or 'i'):gsub('i', Indexes[arg[2] or #Indexes] or '0'))) or '0'
end

-- Returns the resolved or not (arg[3]) string of the desired option (arg[2]) from the desired section (arg[1])
function OptionValue(...)
  local section = arg[1] or SKIN:GetVariable('CURRENTSECTION')
  local functional, visual = SKIN:GetMeasure(section), SKIN:GetMeter(section)
  return ((functional or visual) and (functional or visual):GetOption(arg[2] or (functional and 'Measure' or 'Meter'), '', arg[3]) or '')
end

function SI(...) local I = {}; for i in (arg[1] or SKIN:GetVariable('CURRENTSECTION')):gmatch('%d+') do I[#I + 1] = i end; return tostring(SKIN:ParseFormula((arg[3] or 'i'):gsub('i', I[arg[2] or #I] or '0'))) or '0' end

function OV(...) local s = arg[1] or SKIN:GetVariable('CURRENTSECTION'); local f, v = SKIN:GetMeasure(s), SKIN:GetMeter(s); return ((f or v) and (f or v):GetOption(arg[2] or (f and 'Measure' or 'Meter'), '', arg[3]) or '') end
[SkinFolder]\SI.ini:

Code: Select all

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1
BackgroundMode=2
SolidColor=47,47,47,255

---Measures---

[S]
Measure=Script
ScriptFile=#@#S.lua
UpdateDivider=-1

---Meters---

[Re7su3lt5]
Meter=String
FontColor=255,255,255,255
FontFace=Consolas
FontSize=16
Padding=5,5,5,5
AntiAlias=1
;Text=Section  Name = #CURRENTSECTION##CRLF#Section Index = [&S:SI()]#CRLF#Option  Value = [&S:OV()]
Text=Section  Name = #CURRENTSECTION##CRLF#Option  Value = [&S:OV()]#CRLF#Section Index = [&S:SI()]
UpdateDivider=-1
DynamicVariables=1
The Section Index = ... part in the Text option from the above meter is producing the incorrect '0' (printing from Lua gives empty CURRENTSECTION):
SI Bad.jpg
On the other hand, precisely the same part in the commented Text option is producing the correct '5' (I only swapped the 2nd and the 3rd lines there):
SI Good.jpg
Bottom line, the SI() function works, just not if it's the last one in the Text option. Paradoxally, the OV() one works even if it's the last one in the same option. Both functions request the value of CURRENTSECTION from Lua, but the SI() one does it in a FOR statement (though it shouldn't be a problem since the control expressions are only evaluated once before the loop starts). It's possible that this is a consequence of a ... variable number of arguments to the Lua functions, maybe Rainmeter is not properly 'tracking' where the CURRENTSECTION value is used in that case - just guessing here.

P.S. For conveniency in deciphering my abbreviations, I included the (equivalent) "long name versions" of these functions at the top of the script (having the same behavior). If you wonder, it's not about the abbreviations or confusing them with the parameters for section variables, I already checked that.

EDIT: Forgot to explicitly mention this when writing the original post, but the problem seems to originate from not being able to retrieve CURRENTSECTION from both SKIN:GetVariable() and SKIN:ReplaceVariables() - this is easily noticed if doing a print() on them at the start of the SectionIndex() / SI() function(s).
You do not have the required permissions to view the files attached to this post.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
RicardoTM
Posts: 404
Joined: December 28th, 2022, 9:30 pm
Location: México

Re: [BUG] Multiple Lua functions calling CURRENTSECTION

Post by RicardoTM »

The following is part of this discussion, reposted here because it belongs to this thread.

I've tested with 3 functions after the OV function. Both SectionIndex and SI are returning 0 only if they are placed after OV, they both work fine if they're before OV. Both SectionIndex and SI have one thing in common: SKIN:ParseFormula.

Code: Select all

function OV(...) local s = arg[1] or SKIN:GetVariable('CURRENTSECTION'); local f, v = SKIN:GetMeasure(s), SKIN:GetMeter(s); return ((f or v) and (f or v):GetOption(arg[2] or (f and 'Measure' or 'Meter'), '', arg[3]) or '') end

function SI(...) local I = {}; for i in (arg[1] or SKIN:GetVariable('CURRENTSECTION')):gmatch('%d+') do I[#I+1] = i end; return tostring(SKIN:ParseFormula((arg[3] or 'i'):gsub('i', I[arg[2] or #I] or '0'))) or '0' end

function SectionIndex(section, occurrence, formula)
  local indexes = {}
  for index in section:gmatch('%d+') do table.insert(indexes, index) end
  if occurrence == 'first' then occurrence = 1 elseif occurrence == 'last' then occurrence = #indexes end
  return tostring(SKIN:ParseFormula(string.gsub(formula, '<x>', tostring(indexes[tonumber(occurrence)] or '0')))) or '0'
end

So I've added this other function to the test with SKIN:parseFormula:

Code: Select all

function cond2(cond_str, true_str, false_str)
    if SKIN:ParseFormula(SKIN:ReplaceVariables(cond_str)) == 1 then
        return true_str
    else
        return false_str
    end
end
That's one of the conditional functions discussed on this topic. So as I suspected, it doesn't work correctly. This is the measure:

Code: Select all

[12]
Measure=String
String=[&S:OV()][&S:cond2('([#CurrentSection]=12)','1','2')]
UpdateDivider=-1
DynamicVariables=1
it incorrectly returns "String2", instead of the expected "String1" (since the statement 12=12 is true).

If I do the oposite:

Code: Select all

[12]
Measure=String
String=[&S:cond2('([#CurrentSection] = 12)','1','2')][&S:OV()]
UpdateDivider=-1
DynamicVariables=1
Now the result is "1String" which is correct.

So, to try to be sure, I added another function, the simplest:

Code: Select all

function con(cond, true_str, false_str)
    if cond == 0 then
        return false_str
    else
        return true_str
    end
end
If I place it before OV, the result is "1String" as expected

Code: Select all

[12]
Measure=String
String=[&S:con(([#CurrentSection] = 12),'1','2')][&S:OV()]
UpdateDivider=-1
DynamicVariables=1
However, if I do the oposite.

Code: Select all

[12]
Measure=String
String=[&S:OV()][&S:con(([#CurrentSection] = 12),'1','2')]
UpdateDivider=-1
DynamicVariables=1
The result is: String[&S:con(( = 12),'1','2')] :rofl:

This took me to test without any other function:

Code: Select all

[12]
Measure=String
String=[&S:OV()][#CurrentSection]
UpdateDivider=-1
DynamicVariables=1
Which, only returns: "String" (the oposite does return 12String correctly).

Whatever is causing this has to be inside the OV function, since I can use any other function with as many [#CurrentSection]s as I want and they work properly.

Code: Select all

[12]
Measure=String
String=[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]
UpdateDivider=-1
DynamicVariables=1
This returns 12-12-1-1 which is correct.

However this:

Code: Select all

[12]
Measure=String
String=[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]-[&S:OV()]-[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]
UpdateDivider=-1
DynamicVariables=1
returns: 12-12-1-1-String-0--[&S:con(( = 12),'1','2')]-2

*Note I just placed the same before and after [&S:OV()]. The correct result should be 12-12-1-1-String-12-12-1-1

Finally, I tested the same with the original long version of the OV function: OptionValue, but without using [#CurrentSection], I simply used the name of the measure directly (12)

Code: Select all

[12]
Measure=String
String=[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]-[&S:OptionValue('12','Measure',nil)]-[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]
UpdateDivider=-1
DynamicVariables=1
Surprisingly, this doesn't work either, the result is the same: 12-12-1-1-String-0--[&S:con(( = 12),'1','2')]-2

So, I've started changing sections, like selecting other measure/meters and the result was the same, then I tried various options with the same result, until I changed option to nil:

Code: Select all

[12]
Measure=String
String=[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]-[&S:OptionValue('12',nil,nil)]-[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]
UpdateDivider=-1
DynamicVariables=1
The result was: 12-12-1-1--12-12-1-1

So maybe the problem has more to do with GetOption and little with [#CurrentSection].

To test further, I wrote this dummy function:

Code: Select all

function OptionValue2(section, option, resolve)
  return ((SKIN:GetMeasure(section) or SKIN:GetMeter(section)) and option or '')
end
I said dummy because all it does is to return 'option' if the section exists. I just did it to remove the GetOption part of the original function. It works.

Code: Select all

[12]
Measure=String
String=[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]-[&S:OptionValue2('[#CurrentSection]','Hola',nil)]-[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]
UpdateDivider=-1
DynamicVariables=1
This correctly returns: 12-12-1-1-Hola-12-12-1-1. Notice I used [#CurrentSection] on all functions this time.

Sorry for the super long post, I was typing as I was testing.

This appears to indicate that the problem is GetOption.

Conclusion: While I have no idea how, nor why, GetOption may be causing rainmeter to not be able to resolve [#CurrentSection], making it simply an empty line "".


Here's the complete lua file I used to test:

Code: Select all

function SI(...) local I = {}; for i in (arg[1] or SKIN:GetVariable('CURRENTSECTION')):gmatch('%d+') do I[#I+1] = i end; return tostring(SKIN:ParseFormula((arg[3] or 'i'):gsub('i', I[arg[2] or #I] or '0'))) or '0' end

function OV(...) local s = arg[1] or SKIN:GetVariable('CURRENTSECTION'); local f, v = SKIN:GetMeasure(s), SKIN:GetMeter(s); return ((f or v) and (f or v):GetOption(arg[2] or (f and 'Measure' or 'Meter'), '', arg[3]) or '') end

function con(cond, true_str, false_str)
    if cond == 0 then
        return false_str
    else
        return true_str
    end
end

function cond2(cond_str, true_str, false_str)
    if SKIN:ParseFormula(SKIN:ReplaceVariables(cond_str)) == 1 then
        return true_str
    else
        return false_str
    end
end


function SectionIndex(section, occurrence, formula)
  local indexes = {}
  for index in section:gmatch('%d+') do table.insert(indexes, index) end
  if occurrence == 'first' then occurrence = 1 elseif occurrence == 'last' then occurrence = #indexes end
  return tostring(SKIN:ParseFormula(string.gsub(formula, '<x>', tostring(indexes[tonumber(occurrence)] or '0')))) or '0'
end

function OptionValue(section, option, resolve)
  return ((SKIN:GetMeasure(section) or SKIN:GetMeter(section)) and (SKIN:GetMeasure(section) or SKIN:GetMeter(section)):GetOption(option, '', resolve) or '')
end

function OptionValue2(section, option, resolve)
  return ((SKIN:GetMeasure(section) or SKIN:GetMeter(section)) and option or '')
end
Here's the test skin

Code: Select all

[Rainmeter]
Update=-1
AccurateText=1
DynamicWindowSize=1
BackgroundMode=2
SolidColor=47,47,47,255

---Measures---

[S]
Measure=Script
ScriptFile=#@#Script.lua
UpdateDivider=-1

[12]
Measure=String
String=[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]-[&S:OptionValue2('12','Hola',nil)]-[&S:SI()]-[#CurrentSection]-[&S:con(([#CurrentSection] = 12),'1','2')]-[&S:cond2('([#CurrentSection] = 12)','1','2')]
UpdateDivider=-1
DynamicVariables=1

---Meters---

[Re7su3lt5]
Meter=String
FontColor=255,255,255,255
MeasureName=12
FontFace=Consolas
FontSize=16
Padding=5,5,5,5
AntiAlias=1
Text=%1
UpdateDivider=-1
DynamicVariables=1
User avatar
Yincognito
Rainmeter Sage
Posts: 8534
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG] Multiple Lua functions calling CURRENTSECTION

Post by Yincognito »

To simplify things to the max, here's the essence of it (the 1st function call works, the 2nd doesn't)...

[SkinFolder]\@Resources\S.lua:

Code: Select all

function F(n)
  print(SKIN:GetVariable('CURRENTSECTION'))
  local s = SKIN:GetVariable('CURRENTSECTION','M')
  return SKIN:GetMeter(s) and SKIN:GetMeter(s):GetOption('Meter') or 'Error'
end
[SkinFolder]\Skin.ini:

Code: Select all

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1
BackgroundMode=2
SolidColor=0,255,0,255

---Measures---

[S]
Measure=Script
ScriptFile=#@#S.lua
UpdateDivider=-1

---Meters---

[M]
Meter=String
AntiAlias=1
Text=S = #CURRENTSECTION##CRLF#F = [&S:F(0)]#CRLF#F = [&S:F(0)]
UpdateDivider=-1
DynamicVariables=1
Preview:
Lua SI &amp; GO.jpg
Notice how in the 2nd call the default value of 'M' isn't applied in GetVariable() either, besides not printing the current section value. The variable number of arguments doesn't play a part in this, since it has been eliminated to help find the source of the problem.
You do not have the required permissions to view the files attached to this post.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth