Description="KDL"
Categories = {"config"}
-- KDL 2.0.0, plus the KDL 1 spellings of the keywords and of raw strings, as
-- most configuration files in the wild are still written against KDL 1
Identifiers=[[ [a-zA-Z_][\w\-\.]*|[\-\.]+[a-zA-Z_][\w\-\.]* ]]
Digits=[[ [\-\+]?(?:0x[0-9a-fA-F][0-9a-fA-F_]*|0o[0-7][0-7_]*|0b[01][01_]*|\d[\d_]*(?:\.[\d_]+)?(?:[eE][\-\+]?\d[\d_]*)?) ]]
Keywords={
-- the property key must precede the node name: on a line continued with "\"
-- both match, and only this one is right
{ Id=2,
Regex=[[([\w\-\.\x80-\xFF][^\s\(\)\{\}\[\];=\\\/"]*)\s*=]],
},
{ Id=1,
Regex=[[^\s*([\w\-\.\x80-\xFF][^\s\(\)\{\}\[\];=\\\/"]*)]],
},
{ Id=3,
Regex=[[#(?:true|false|null|inf|-inf|nan)]],
},
{ Id=3,
List={"true", "false", "null"}
},
{ Id=4,
Regex=[[\(\s*([^\s\(\)]+)\s*\)]],
},
-- Raw string delimiters, handed to the string state by OnStateChange, which
-- pairs their hashes by length. #"""# holds a quote, it is not a multi line
-- opener; and since "#ff0000" opens a plain string, only close a raw one
-- where a value ends and cannot begin.
{ Id=5,
Regex=[[#+"""(?!#)|#+"]]
},
{ Id=6,
Regex=[["""#+]]
},
{ Id=6,
Regex=[[[^\s=]("#+)(?=[\s;\)\}=]|$)]],
},
}
Strings={
Delimiter=[["""|"]],
AssertEqualLength=true,
RawPrefix="r",
-- \" is an escape everywhere except as the tail of a raw string terminator
Escape=[[ \\u\{[0-9a-fA-F]{1,6}\}|\\[nrtsbf\\\/]|\\"(?!#+(?:[\s;\)\}=]|$)) ]],
}
IgnoreCase=false
Comments={
-- "/*" and a slashdashed node with a child block share one nesting counter,
-- so a "}" ends a block comment opened inside a commented out node. The bare
-- "{" alternative is what feeds the counter the inner blocks.
{ Block=true,
Nested=true,
Delimiter= { [[\/\*|\/\-[^\{\}]*\{|\{]], [[\*\/|\}]] }
},
-- slashdash without a child block: the node ends with the line
{ Block=false,
Delimiter= { [[\/\-]] }
},
{ Block=false,
Delimiter= { [[\/\/]] }
},
}
Operators=[[\(|\)|\{|\}|\;|\=|\\]]
function OnStateChange(oldState, newState, token, groupID)
-- braces delimit a comment only while a slashdashed node is being skipped
if (token=="{" or token=="}") and oldState~=HL_BLOCK_COMMENT then
return HL_OPERATOR
end
if groupID==5 then
-- inside a string the hashes are content, and the quote closes it
if oldState==HL_STRING then
return HL_REJECT
end
OverrideParam("state.string.raw", "true")
return HL_STRING
end
if groupID==6 and oldState==HL_STRING then
return HL_STRING_END
end
return newState
end