That's the only thing I meant with the IN statement. Don't want to have any more list-stuff in dogtags. Just that stuff like that saves space and saves comparisons.
Re-read my tag. I don't ever want to see the unit's classification (or creature type/family) there -- only the unit's level. The Classifcation tag is in there because I want to hide the level for units that are classified as a Boss, but I can't simply :Hide(??) because I still want to see the question marks for enemy players, pets, and normal mobs that are high-level. I also don't want to see the level for units that are Critters or Non-combat Pets. The only thing that tag should ever display is a level.
As for the ~= issue... it didn't work the last time I tried it, but admittedly that was back before the ~Status bug was fixed. I'll give it another go.
Quote from Nayala »
Change the piping / modifier option to be a prefix, and use something like "->" for it. e.g. "[PowerColor->CurMP]". The benefit is that above any confusion with what part of an if then else expansion gets the modifier.
Allow nested brackets or parenthesis to force precedence but try to avoid users even needing to worry about them. As an extension consider using following lua's example and using matching brackets pairs for example: ]=> only matching <=[, ]==> matching <==[ etc. This means that if someone needs/wants to use nesting brackets they can at least make it easier to follow. e.g. "... [a ? [b ? c : d] : e] ..." or "... <=[ a ? <==[ b ? c : d ]==> : e ]=> ...".
Please, no. Talk about ugly clutter and totally unnecessary tag length and complication. If you have that much trouble following nested brackets, edit your tags out-of-game in a text editor where you can use multiple lines and indentation. And I really don't think that [PowerColor->Short->Hide(0)->Hide([MaxMP])->CurMP] would in any way be easier for non-programming users than [CurMP:Hide([MaxMP]):Hide(0):Short:PowerColor].
Quote from Nayala »
... But allow bare words that are not tags to be also treated as literal text. A good tag editor should highlight such tags however.
I don't think this is a good idea. First, it would be a waste of processor time to check every word to see if it was a tag or literal text. Second, it's lazy, and can only lead to confusion after the fact. Let's say I just downloaded PitBull and I have no idea how DogTags work, but I've seen all these cool screenshots, so I'm browsing the "Post your DogTags" thread to find some nifty texts. Let's say I see one that looks almost perfect, and I'm feeling adventurous and want to make a tiny change. I have no idea what's a tag and what's text. Or let's say you wrote a long complex DogTag sequence, and a week later you want to change something; without quotes you have to waste time and energy remembering what's a tag and what's not. If people are too lazy to type quotation marks around their literal text, they deserve errors.
Quote from Ellipsis »
And wrt the exact details of the tag consistency rules - someone suggested boolean tags should all start with Is or Has, but I am more in favor of turning all boolean tags into string/nil returns. That way, they can still be used as a boolean condition, but simplify basic tasks for users. For example the (currently nonexistent) tag [IsMainTank], returning "True" or "", should instead be [MainTank], returning "Main Tank" or "". [MainTank? "Heals plz!" ! "I pull aggroz"] works with either one, but the latter tag can be used to put "Main Tank" on main tank frames with [MainTank] whereas otherwise you'd need [IsMainTank? "Main Tank"], which seems a bit redundant. Not the most practical example, since most people don't want "Main Tank" all over their tanks' health bars, but it would probably be useful with :Trunc() or :Abbreviate().
For that tag, I think [MainTank] would be appropriate, as it could be useful to have "Main Tank" or "MT" displayed as text; however, for things like [IsPlayer], I think a boolean value is appropriate, as there isn't really any use for having "Player" or "Not Player" displayed.
Another consistency question (though more of a backend one than a user-noticeable one) is the fact that there are some tags that take one argument and some modifiers that take none; really, they could go either way (except in cases like [ShortClass] or color tags, where the tag and modifier both already exist with different meanings). [Percent(PercentHP)] is theoretically just as valid as [PercentHP:Percent], and there's no real reason why you can't do [Floor(CastEndTime)] instead of [CastEndTime:Floor].
[if IsFriend then
if Status then
" | " HPColor(Status)
else
if MissingHP ~= 0 then
" | " HPColor(Short(MissingHP))
else -- how do you know which if this belongs to
if ~IsMaxHP and ~Status then
" | " Color(VeryShort(MaxHP), "6666cc")
]
Admittedly it's a bit contrived because I replaced HideZero and the Status:MissingHP piping with if/then, but I don't think it's too far-fetched.
Considering if-then-else is an expression and not a construct (and that parenthesis is used for internal grouping). You could go with :
[if IsFriend then (
if Status then
" | " HPColor(Status)
else
if MissingHP ~= 0 then
" | " HPColor(Short(MissingHP))
) else
if ~IsMaxHP and ~Status then
" | " Color(VeryShort(MaxHP), "6666cc")
]
I must admit that it defeats the purpose of the verbose form of "if-then-else". An "end" keyword could be useful, indeed.
Another approach is allowing only "single expression" in condition, then and else part. Using parenthesis would be required.
[if IsFriend then (
if Status then (
" | " HPColor(Status)
) else (
if MissingHP ~= 0 then
(" | " HPColor(Short(MissingHP)))
)
) else (
if (~IsMaxHP and ~Status) then (
" | " Color(VeryShort(MaxHP), "6666cc")
)
)]
But it looks like C, isn't really simple and would become unreadble if put in one line :
[if IsFriend then (if Status then (" | " HPColor(Status)) else (if MissingHP ~= 0 then (" | " HPColor(Short(MissingHP))))) else (if (~IsMaxHP and ~Status) then (" | " Color(VeryShort(MaxHP), "6666cc")))]
Re-read my tag. I don't ever want to see the unit's classification (or creature type/family) there -- only the unit's level. The Classifcation tag is in there because I want to hide the level for units that are classified as a Boss, but I can't simply :Hide(??) because I still want to see the question marks for enemy players, pets, and normal mobs that are high-level. I also don't want to see the level for units that are Critters or Non-combat Pets. The only thing that tag should ever display is a level.
As for the ~= issue... it didn't work the last time I tried it, but admittedly that was back before the ~Status bug was fixed. I'll give it another go.
My bad, I'm not sure what I was thinking when I was reading your tag. However, tags like [Classification ~= Text(Boss) ? Level:DifficultyColor] should work - if it doesn't, there's a bug there. :P
Quote from Phanx »
For that tag, I think [MainTank] would be appropriate, as it could be useful to have "Main Tank" or "MT" displayed as text; however, for things like [IsPlayer], I think a boolean value is appropriate, as there isn't really any use for having "Player" or "Not Player" displayed.
True, but is there really any harm in a [Player] tag that returns "Player" or ""? Since it can still be used in conditionals, it offers all the functionality that [IsPlayer] does, and (correct me if I'm wrong, ckknight) there's no performance penalty, since it's just returning one string rather than another.
There's always the one-in-a-million user who wants to do something really strange with their DogTags...
True. Although what would you do with [IsPlayerOrPet]? Have it return either "Player" or "Pet" or ""? Or make users do [IsPlayer ? IsPet] instead?
[IsPlayerOrPet] could remain a "True"/"" return, or it could be changed to [PlayerOrPet] and return "Player"/"Pet"/"" since, from a user perspective, it's an alias for [IsPlayer | IsPet] (of course, the code behind it works somewhat differently, but that would be consistent with how the documentation reads). And with that functionality, I can see someone using [PlayerOrPet] as-is, in a tooltip or something.
I assume you're not going to use newline stuff because you want to keep statements all in one block. This is fine, but realize the main problem this creates is multiple lines and indentation make it easy to follow a logical evaluation whereas in one line it gets complicated. I think understanding the nested test conditions and evaluations is what drives most people mad when establishing new sequences, so I'd humbly suggest a color coding system to make it easier to follow than having that one line all monochrome.
is my nested logic to determine for Cowtips showing the player tooltip if 70 show reputation else show experience points. Given the internal collapser and figuring out my brackets drove me batty trying to get it right. I think I'd have a much easier time with:
so I could get the same information as indentation allows normal code but in one-line format and when the system goes hog wild collapsing my statements to save space or deciding it knows best what I'm thinking I could see where I need to properly assert myself to have the evaluation complete as I intended
We could also get rid of all that parenthesis stuff with RPN (assuming "?!" is the if-then-else operator, "?" is "if-then", ".." is string concatenation):
[IsFriend Status " | " Status HPColor .. MissingHP 0 ~= " | " MissingHP Short HPColor .. ? ?! IsMaxHP ~ Status ~ and " | " MaxHP VeryShort "6666cc" Color .. ? ?!]
I'm obviously kidding. I would prefer construct like:
Adirelle, in making DogTags simpler, I don't think RPN is the best idea. People aren't used to prefix or postfix notation for operations, infix, although harder to parse for computers, makes more sense for people.
Looking at all the post here I'm becoming to wonder why we are still using the square brackets around whole tag when all people is using round ones.
From my perspective the [] specifies a tag and () specifies a parameters for function/modulator/... The square brackets are optional when the tag is trivial (one tag/concatenation of tags)
I also suggest using C style operators: ! for NOT, ? : for IF/ELSE, & for AND, | for OR and =, !=, >, < ....
- NOT returns True/False
- AND/OR return logic is same as in Lua
- Comparison operators return True or False
- IF/ELSE statement returns only one of its part (or False/nil if else part is empty)
- False is never displayed in output (as nil); True? TBD
Because : is used as ELSE there has to be another character for modifiers. In Lua and C we use . (dot) when working with objects.
Concatenation should be done automatically
When complicated conditions (mixing ANDs/ORs) are needed the square brackets are used. [Alpha & Beta] is proper tag returning True/False so we can use: [ [Alpha & Beta] & [Gama | !Charlie] ? "True" : "False" ]
Operator precedence is: modifiers/piping, NOT, comparison (=, !=, >, ...), AND/OR, concatenation, IF/ELSE.
All should be evaluated from left-to right and IF/ELSE couldn't be included in itself directly - only via subtag in [] (ie: [?: ?:] is illegal, [?:[?:]] is only correct way. more complicated example: [?[?:[?]]:[?]])
So basic structure should be:
[CurHP "/" MaxHP] -- the brackets are optional
[CurHP = MaxHP ? "Full" : CurHP "/" MaxHP] -- shows HP only when damaged - concatenation takes precedence over the end of IF/ELSE statement
[[CurHP = MaxHP ? "Full" : CurHP "/"] MaxHP] -- shows max HP always; current HP only when damaged
[CurHP != MaxHP ? CurHP.Hide(0).Short] -- piping example
[CurHP = MaxHP & CurMP = MaxMP ? "Ready" : ["HP: " CurHP "/" MaxHP].HPColor ["MP: " CurMP "/" MaxMP].MPColor ] -- piping example on concatenated tags
And some examples posted before:
- [IsUnit(player)?[IsMaxLevel?[FractionalRep:Bracket]![FractionalXP:Bracket]]:Color(FFCC00)] will become
[IsUnit(player) & IsMaxLevel ? FractionalRep.Bracket : FractionalXP.Bracket.Color(FFCC00)]
- [ [IsPlayerOrPet ? IsFriend] ? [Classification:Hide(Non-combat Pet) | Level:Hide(70):Color(ccccff)] ! [Classification:Hide(Boss):Hide(Critter) | Level:DifficultyColor] ] will become
[IsPlayerOrPet & IsFriend ? [Classification.Hide("Non-combat Pet") | Level.Hide(70).Color(ccccff)] : [Classification.Hide("Boss").Hide("Critter") | Level.DifficultyColor]
-
[if IsFriend then
if Status then
" | " HPColor(Status)
else
if MissingHP ~= 0 then
" | " HPColor(Short(MissingHP))
else -- how do you know which if this belongs to
if ~IsMaxHP and ~Status then
" | " Color(VeryShort(MaxHP), "6666cc")
]
will become [?[?:[?]]:[?]]
[IsFriend ?
[Status ?
" | " Status.HPColor -- concatenation takes precedence so bracketing the tag is not needed
:
[MissingHP ~= 0 ? " | " MissingHP.Short.HPColor] -- another IF, needs to be bracketed as another tag
]
:
[!IsMaxHP & !Status ? " | " MaxHP.VeryShort.Color("6666cc")]
]
There is one issue which was not covered in any posts: Mouse-over conditionals. (IIRC done by #mouseover) - this could be rewritten using normal tag [IsMouseOver] ;) If such tags needs special handling the preprocessor can take notice based on the tag name, but the users wouldn't need to learn something else just for this case ;)
Looking at all the post here I'm becoming to wonder why we are still using the square brackets around whole tag when all people is using round ones.
From my perspective the [] specifies a tag and () specifies a parameters for function/modulator/... The square brackets are optional when the tag is trivial (one tag/concatenation of tags)
I also suggest using C style operators: ! for NOT, ? : for IF/ELSE, & for AND, | for OR and =, !=, >, < ....
- NOT returns True/False
- AND/OR return logic is same as in Lua
- Comparison operators return True or False
- IF/ELSE statement returns only one of its part (or False/nil if else part is empty)
- False is never displayed in output (as nil); True? TBD
DogTag doesn't actually have true or false values. Every return is either a number or a string. "" is a special string that evaluates as false in conditionals, but all other strings evaluate as true. Negation turns non-blank values into blank ones, and blank ones into "True". Comparisons return the first argument if true, otherwise they return "". This is so you can do things like [CurHP >= 500] instead of [CurHP:HideLess(500)]. I don't see any reason to change any of this - there's no need for a boolean type in DogTag, especially since (IMO) tags should never return "True" by themselves.
There is one issue which was not covered in any posts: Mouse-over conditionals. (IIRC done by #mouseover) - this could be rewritten using normal tag [IsMouseOver] ;) If such tags needs special handling the preprocessor can take notice based on the tag name, but the users wouldn't need to learn something else just for this case ;)
#mouseover and [IsMouseOver] aren't the same thing. Normally, if I put [ClassColor] on my target frame, it will show the text in the target's class color. If I want to show it with my class color instead, I'd do [ClassColor#player]. I suppose you could show it in your mouseover target's class color with [ClassColor#mouseover] but that doesn't seem very useful.
On a more general note, I've seen about 50 different proposed syntax examples in this thread, and I have to say, I think you guys are trying to change too much. The great majority of people using PitBull, CowTip, and other DogTag addons are not programmers, and already had enough trouble learning the [condition ? iftrue ! iffalse] syntax. Changing that so radically as some have suggested won't improve matters for the majority, and it seems that everyone with a new syntax suggestion is basing it off their favorite programming language, so it won't improve matters for the rest of the programming minority who may not like or even know your favorite language. Keep the ?, keep the !, keep the |, keep the square brackets, add an & operator, add concatenation by juxtaposition, change modifiers to work as either tag:modifier or modifier(tag), change tag names to adhere to a consistent naming convention, and you'll be good.
I think if most people wanted to write their own code (and to non-programmers, if ... then ... else is definitely code, whereas [... ? ... ! ...] is less scary), they'd just modify the DogTag library Lua directly to output their desired result to a custom tag, which is what I did for quite some time before DogTag was able to do what I wanted normally. I don't think I still have any modified copies laying around, but bascially I just deleted all of the existing DogTags and added my own... for example, my [LongHealth] tag went something like:
if UnitIsDeadOrGhost(unit) then
if UnitIsGhost(unit) then
return "|cffaaaaaaGhost|r"
else
return "|cffaaaaaaDead|r"
end
else
local cur, max = UnitHealth(unit), UnitHealthMax(unit)
if MobHealth3 then
cur, max = MobHealth3:GetHealth(unit)
end
if max ~= 100 then
if cur ~= max then
if UnitIsFriend(unit) then
return cur.." - "..max - cur
else
return cur.." ("..floor( cur / max ).."%)"
end
else
returncur
end
else
return floor( cur / max ).."%"
end
end
However, it's much easier now (although probably significantly more CPU-intensive to parse) just to do it in-game with DogTag syntax, like so:
But there's not really any difference between my Lua code and some of the proposed syntaxes, other than using DogTag tags instead of WoW API functions. :P
#mouseover and [IsMouseOver] aren't the same thing. Normally, if I put [ClassColor] on my target frame, it will show the text in the target's class color. If I want to show it with my class color instead, I'd do [ClassColor#player]. I suppose you could show it in your mouseover target's class color with [ClassColor#mouseover] but that doesn't seem very useful.
Another time I didn't fully understand the problem :( I've used this syntax in my player Pitbull frame just to display detailed info on mouseover and nothing else.
Quote from Phanx »
On a more general note, I've seen about 50 different proposed syntax examples in this thread, and I have to say, I think you guys are trying to change too much. The great majority of people using PitBull, CowTip, and other DogTag addons are not programmers, and already had enough trouble learning the [condition ? iftrue ! iffalse] syntax.
Here lies my biggest problem with current DogTag. When I tried to learn it documentation said ? = AND and ! = OR. The [condition ? iftrue ! iffalse] syntax comes from the Lua style of expression handling and can be hard to comprehend. When looking at some tags which uses more ANDs and ORs it becomes much more harder... Some of the proposals here suggest creating special IF/ELSE construct for the tags to be more easier to understand.
Personally I don't mind which symbols are used - we can still use ? ! for IF/ELSE, & for AND, | for OR and ~ for NOT. The point is I'd like to differentiate IF/ELSE from AND and OR.
With this, concatenation and adding subtags your [LongHealth] tag can look like (using unchanged operators) which resolves more to your Lua code ;) or could be left alone in its current form.
[Status ? Status:Color(aaaaaa) ! [SureHP ? CurHP:Short [IsFriend ? MissingHP:Hide(0):Short:Prepend("- "):Color(ffaaaa) ! PercentHP:Hide(100):Floor:Percent:Paren] ! PercentHP:Hide(100):Floor:Percent] ]
Quote from Ellipsis »
DogTag doesn't actually have true or false values. Every return is either a number or a string. "" is a special string that evaluates as false in conditionals, but all other strings evaluate as true. Negation turns non-blank values into blank ones, and blank ones into "True". Comparisons return the first argument if true, otherwise they return "". This is so you can do things like [CurHP >= 500] instead of [CurHP:HideLess(500)]. I don't see any reason to change any of this - there's no need for a boolean type in DogTag, especially since (IMO) tags should never return "True" by themselves.
If all the base tags are changed to return actual strings it will be much more useful. I still have problem with comparison operators though. The expression 10 > 5 evaluates to "10", which is True, but it is weird. What is the result of equality comparison of two empty strings? HasAura("Some Poison") = HasAura("Some Cure") should be True, when player is ok or when he is poisoned and has cure.
I think if most people wanted to write their own code (and to non-programmers, if ... then ... else is definitely code, whereas [... ? ... ! ...] is less scary), they'd just modify the DogTag library Lua directly to output their desired result to a custom tag
I disagree. Using [ cond ? if_true ! if_false ] is way more arcane than using english words. These changes aren't just to make things easier for current DogTag users but for new users too. New users are going to learn from reading examples and the readability of the current DogTag syntax leaves much to be desired.
Quote from Phanx »
for example, my [LongHealth] tag went something like:
if UnitIsDeadOrGhost(unit) then
if UnitIsGhost(unit) then
return "|cffaaaaaaGhost|r"
else
return "|cffaaaaaaDead|r"
end
else
local cur, max = UnitHealth(unit), UnitHealthMax(unit)
if MobHealth3 then
cur, max = MobHealth3:GetHealth(unit)
end
if max ~= 100 then
if cur ~= max then
if UnitIsFriend(unit) then
return cur.." - "..max - cur
else
return cur.." ("..floor( cur / max ).."%)"
end
else
returncur
end
else
return floor( cur / max ).."%"
end
end
However, it's much easier now (although probably significantly more CPU-intensive to parse) just to do it in-game with DogTag syntax, like so:
But there's not really any difference between my Lua code and some of the proposed syntaxes, other than using DogTag tags instead of WoW API functions. :P
Your lua is more complicated because it doesn't have all of the helper functions that Dogtag provides.
If the values of all of the tags you use were available as upvalues and the modifiers were available as functions, your lua would look more like this:
if IsDeadOrGhost then
return Color(Status, "aaaaaa")
else
if SureHP then
if IsFriend then
if MissingHP ~= 0 then
return Short(CurHP) .. " " ..
Color("- " .. Short(MissingHP), "ffaaaa")
else
return Short(CurHP)
end
else
return Short(CurHP) .. " (" .. Floor(PercentHP) .. "%)"
end
else
if PercentHP ~= 100 then
return Floor(PercentHP) .. "%"
end
end
end
It's still significantly longer than the DogTag. I also favor the current [A ? [B ? C ! D] ! E] syntax because it's very easy to work with in a text editor that has visual brace matching, even if it's all on one line. Compare...
Your propoasl:
if IsDeadOrGhost then return Color(Status, "aaaaaa") else if SureHP then if IsFriend then if MissingHP ~= 0 then return Short(CurHP) .. " " .. Color("- " .. Short(MissingHP), "ffaaaa") else return Short(CurHP) end else return Short(CurHP) .. " (" .. Floor(PercentHP) .. "%)" end else if PercentHP ~= 100 then return Floor(PercentHP) .. "%" end end end
Which one is easier to read and understand on one line?
Not to mention that I don't even want to think about how such a verbose if-then-else-end syntax would lengthen some of my other tags.
Agreed, but multiple lines without indentation is even worse, and every implementation of tab indentation I've seen in WoW has been buggy to the point of being unusably annoying.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
Per IRC, I wasn't advocating list-manipulation just checking set membership via varargs to condense multiple comparisons.
Re-read my tag. I don't ever want to see the unit's classification (or creature type/family) there -- only the unit's level. The Classifcation tag is in there because I want to hide the level for units that are classified as a Boss, but I can't simply :Hide(??) because I still want to see the question marks for enemy players, pets, and normal mobs that are high-level. I also don't want to see the level for units that are Critters or Non-combat Pets. The only thing that tag should ever display is a level.
As for the ~= issue... it didn't work the last time I tried it, but admittedly that was back before the ~Status bug was fixed. I'll give it another go.
Please, no. Talk about ugly clutter and totally unnecessary tag length and complication. If you have that much trouble following nested brackets, edit your tags out-of-game in a text editor where you can use multiple lines and indentation. And I really don't think that [PowerColor->Short->Hide(0)->Hide([MaxMP])->CurMP] would in any way be easier for non-programming users than [CurMP:Hide([MaxMP]):Hide(0):Short:PowerColor].
I don't think this is a good idea. First, it would be a waste of processor time to check every word to see if it was a tag or literal text. Second, it's lazy, and can only lead to confusion after the fact. Let's say I just downloaded PitBull and I have no idea how DogTags work, but I've seen all these cool screenshots, so I'm browsing the "Post your DogTags" thread to find some nifty texts. Let's say I see one that looks almost perfect, and I'm feeling adventurous and want to make a tiny change. I have no idea what's a tag and what's text. Or let's say you wrote a long complex DogTag sequence, and a week later you want to change something; without quotes you have to waste time and energy remembering what's a tag and what's not. If people are too lazy to type quotation marks around their literal text, they deserve errors.
For that tag, I think [MainTank] would be appropriate, as it could be useful to have "Main Tank" or "MT" displayed as text; however, for things like [IsPlayer], I think a boolean value is appropriate, as there isn't really any use for having "Player" or "Not Player" displayed.
Another consistency question (though more of a backend one than a user-noticeable one) is the fact that there are some tags that take one argument and some modifiers that take none; really, they could go either way (except in cases like [ShortClass] or color tags, where the tag and modifier both already exist with different meanings). [Percent(PercentHP)] is theoretically just as valid as [PercentHP:Percent], and there's no real reason why you can't do [Floor(CastEndTime)] instead of [CastEndTime:Floor].
Any thoughts on these issues?
[/quote]
Considering if-then-else is an expression and not a construct (and that parenthesis is used for internal grouping). You could go with :
I must admit that it defeats the purpose of the verbose form of "if-then-else". An "end" keyword could be useful, indeed.
Another approach is allowing only "single expression" in condition, then and else part. Using parenthesis would be required.
But it looks like C, isn't really simple and would become unreadble if put in one line :
My bad, I'm not sure what I was thinking when I was reading your tag. However, tags like [Classification ~= Text(Boss) ? Level:DifficultyColor] should work - if it doesn't, there's a bug there. :P
True, but is there really any harm in a [Player] tag that returns "Player" or ""? Since it can still be used in conditionals, it offers all the functionality that [IsPlayer] does, and (correct me if I'm wrong, ckknight) there's no performance penalty, since it's just returning one string rather than another.
There's always the one-in-a-million user who wants to do something really strange with their DogTags...
[IsPlayerOrPet] could remain a "True"/"" return, or it could be changed to [PlayerOrPet] and return "Player"/"Pet"/"" since, from a user perspective, it's an alias for [IsPlayer | IsPet] (of course, the code behind it works somewhat differently, but that would be consistent with how the documentation reads). And with that functionality, I can see someone using [PlayerOrPet] as-is, in a tooltip or something.
[IsUnit(player)?[IsMaxLevel?[FractionalRep:Bracket]![FractionalXP:Bracket]]:Color(FFCC00)]
is my nested logic to determine for Cowtips showing the player tooltip if 70 show reputation else show experience points. Given the internal collapser and figuring out my brackets drove me batty trying to get it right. I think I'd have a much easier time with:
[IsUnit(player)?[IsMaxLevel?[FractionalRep:Bracket]![FractionalXP:Bracket]]:Color(FFCC00)]
so I could get the same information as indentation allows normal code but in one-line format and when the system goes hog wild collapsing my statements to save space or deciding it knows best what I'm thinking I could see where I need to properly assert myself to have the evaluation complete as I intended
I'm obviously kidding. I would prefer construct like:
[condition ? iftrue]
[condition ? iftrue ! iffalse]
Or even :
[If(condition, iftrue)]
[IfElse(condition, iftrue, iffalse)]
;)
From my perspective the [] specifies a tag and () specifies a parameters for function/modulator/... The square brackets are optional when the tag is trivial (one tag/concatenation of tags)
I also suggest using C style operators: ! for NOT, ? : for IF/ELSE, & for AND, | for OR and =, !=, >, < ....
- NOT returns True/False
- AND/OR return logic is same as in Lua
- Comparison operators return True or False
- IF/ELSE statement returns only one of its part (or False/nil if else part is empty)
- False is never displayed in output (as nil); True? TBD
Because : is used as ELSE there has to be another character for modifiers. In Lua and C we use . (dot) when working with objects.
Concatenation should be done automatically
When complicated conditions (mixing ANDs/ORs) are needed the square brackets are used. [Alpha & Beta] is proper tag returning True/False so we can use: [ [Alpha & Beta] & [Gama | !Charlie] ? "True" : "False" ]
Operator precedence is: modifiers/piping, NOT, comparison (=, !=, >, ...), AND/OR, concatenation, IF/ELSE.
All should be evaluated from left-to right and IF/ELSE couldn't be included in itself directly - only via subtag in [] (ie: [?: ?:] is illegal, [?:[?:]] is only correct way. more complicated example: [?[?:[?]]:[?]])
So basic structure should be:
[CurHP "/" MaxHP] -- the brackets are optional
[CurHP = MaxHP ? "Full" : CurHP "/" MaxHP] -- shows HP only when damaged - concatenation takes precedence over the end of IF/ELSE statement
[[CurHP = MaxHP ? "Full" : CurHP "/"] MaxHP] -- shows max HP always; current HP only when damaged
[CurHP != MaxHP ? CurHP.Hide(0).Short] -- piping example
[CurHP = MaxHP & CurMP = MaxMP ? "Ready" : ["HP: " CurHP "/" MaxHP].HPColor ["MP: " CurMP "/" MaxMP].MPColor ] -- piping example on concatenated tags
And some examples posted before:
- [IsUnit(player)?[IsMaxLevel?[FractionalRep:Bracket]![FractionalXP:Bracket]]:Color(FFCC00)] will become
[IsUnit(player) & IsMaxLevel ? FractionalRep.Bracket : FractionalXP.Bracket.Color(FFCC00)]
- [ [IsPlayerOrPet ? IsFriend] ? [Classification:Hide(Non-combat Pet) | Level:Hide(70):Color(ccccff)] ! [Classification:Hide(Boss):Hide(Critter) | Level:DifficultyColor] ] will become
[IsPlayerOrPet & IsFriend ? [Classification.Hide("Non-combat Pet") | Level.Hide(70).Color(ccccff)] : [Classification.Hide("Boss").Hide("Critter") | Level.DifficultyColor]
-
will become [?[?:[?]]:[?]]
There is one issue which was not covered in any posts: Mouse-over conditionals. (IIRC done by #mouseover) - this could be rewritten using normal tag [IsMouseOver] ;) If such tags needs special handling the preprocessor can take notice based on the tag name, but the users wouldn't need to learn something else just for this case ;)
DogTag doesn't actually have true or false values. Every return is either a number or a string. "" is a special string that evaluates as false in conditionals, but all other strings evaluate as true. Negation turns non-blank values into blank ones, and blank ones into "True". Comparisons return the first argument if true, otherwise they return "". This is so you can do things like [CurHP >= 500] instead of [CurHP:HideLess(500)]. I don't see any reason to change any of this - there's no need for a boolean type in DogTag, especially since (IMO) tags should never return "True" by themselves.
#mouseover and [IsMouseOver] aren't the same thing. Normally, if I put [ClassColor] on my target frame, it will show the text in the target's class color. If I want to show it with my class color instead, I'd do [ClassColor#player]. I suppose you could show it in your mouseover target's class color with [ClassColor#mouseover] but that doesn't seem very useful.
On a more general note, I've seen about 50 different proposed syntax examples in this thread, and I have to say, I think you guys are trying to change too much. The great majority of people using PitBull, CowTip, and other DogTag addons are not programmers, and already had enough trouble learning the [condition ? iftrue ! iffalse] syntax. Changing that so radically as some have suggested won't improve matters for the majority, and it seems that everyone with a new syntax suggestion is basing it off their favorite programming language, so it won't improve matters for the rest of the programming minority who may not like or even know your favorite language. Keep the ?, keep the !, keep the |, keep the square brackets, add an & operator, add concatenation by juxtaposition, change modifiers to work as either tag:modifier or modifier(tag), change tag names to adhere to a consistent naming convention, and you'll be good.
I think if most people wanted to write their own code (and to non-programmers, if ... then ... else is definitely code, whereas [... ? ... ! ...] is less scary), they'd just modify the DogTag library Lua directly to output their desired result to a custom tag, which is what I did for quite some time before DogTag was able to do what I wanted normally. I don't think I still have any modified copies laying around, but bascially I just deleted all of the existing DogTags and added my own... for example, my [LongHealth] tag went something like:
However, it's much easier now (although probably significantly more CPU-intensive to parse) just to do it in-game with DogTag syntax, like so:
But there's not really any difference between my Lua code and some of the proposed syntaxes, other than using DogTag tags instead of WoW API functions. :P
Another time I didn't fully understand the problem :( I've used this syntax in my player Pitbull frame just to display detailed info on mouseover and nothing else.
Here lies my biggest problem with current DogTag. When I tried to learn it documentation said ? = AND and ! = OR. The [condition ? iftrue ! iffalse] syntax comes from the Lua style of expression handling and can be hard to comprehend. When looking at some tags which uses more ANDs and ORs it becomes much more harder... Some of the proposals here suggest creating special IF/ELSE construct for the tags to be more easier to understand.
Personally I don't mind which symbols are used - we can still use ? ! for IF/ELSE, & for AND, | for OR and ~ for NOT. The point is I'd like to differentiate IF/ELSE from AND and OR.
With this, concatenation and adding subtags your [LongHealth] tag can look like (using unchanged operators) which resolves more to your Lua code ;) or could be left alone in its current form.
[Status ? Status:Color(aaaaaa) ! [SureHP ? CurHP:Short [IsFriend ? MissingHP:Hide(0):Short:Prepend("- "):Color(ffaaaa) ! PercentHP:Hide(100):Floor:Percent:Paren] ! PercentHP:Hide(100):Floor:Percent] ]
If all the base tags are changed to return actual strings it will be much more useful. I still have problem with comparison operators though. The expression 10 > 5 evaluates to "10", which is True, but it is weird. What is the result of equality comparison of two empty strings? HasAura("Some Poison") = HasAura("Some Cure") should be True, when player is ok or when he is poisoned and has cure.
I disagree. Using [ cond ? if_true ! if_false ] is way more arcane than using english words. These changes aren't just to make things easier for current DogTag users but for new users too. New users are going to learn from reading examples and the readability of the current DogTag syntax leaves much to be desired.
Your lua is more complicated because it doesn't have all of the helper functions that Dogtag provides.
If the values of all of the tags you use were available as upvalues and the modifiers were available as functions, your lua would look more like this:
Current:
[Status ? Status:Color(aaaaaa) ! [SureHP ? CurHP:Short ! PercentHP:Hide(100):Floor:Percent] ] [~Status ? [SureHP ? [IsFriend ? MissingHP:Hide(0):Short:Prepend(- ):Color(ffaaaa) ! PercentHP:Hide(100):Floor:Percent:Paren] ] ]
Your propoasl:
if IsDeadOrGhost then return Color(Status, "aaaaaa") else if SureHP then if IsFriend then if MissingHP ~= 0 then return Short(CurHP) .. " " .. Color("- " .. Short(MissingHP), "ffaaaa") else return Short(CurHP) end else return Short(CurHP) .. " (" .. Floor(PercentHP) .. "%)" end else if PercentHP ~= 100 then return Floor(PercentHP) .. "%" end end end
Which one is easier to read and understand on one line?
Not to mention that I don't even want to think about how such a verbose if-then-else-end syntax would lengthen some of my other tags.