IDE: Optimization of modification events processing in text editors.
Too many modifications types where registered, and then too many events were fired.
Also, in case of uninterrupted sequence of events, updates to the model is deferred to the end of that sequence (wx.Callafter).
// parse_labels.ysl2
// Parses:
// "HMI:WidgetType|freq:param1:param2@a=path1,path1min,path1max@b=path2#a+b>3"
//
// Into:
// widget type="WidgetType" id="blah456" {
// arg value="param1";
// arg value="param2";
// path value=".path1" index=".path1" min="path1min" max="path1max" type="PAGE_LOCAL";
// path value="/path1" index="348" type="HMI_INT";
// path value="path4" index="path4" type="HMI_LOCAL";
// }
//
const "pathregex",!"'^(\w+=)?([^,=]+)([-.\d,]*)$'"!;
const "newline" |
const "twonewlines", "concat($newline,$newline)";
template "*", mode="parselabel"
{
const "label","@inkscape:label";
const "desc", "svg:desc";
// add svg:desc field if continuation "\" marker is found at the end of label
const "len","string-length($label)";
const "has_continuation", "substring($label,$len,1)='\\'";
const "full_decl" choose{
when "$has_continuation" {
const "_continuation", "substring-before($desc, $twonewlines)";
const "continuation" choose {
when "$_continuation" value "$_continuation";
otherwise value "$desc";
}
value "concat(substring($label,1,$len - 1),translate($continuation,$newline,''))";
}
otherwise value "$label";
}
const "id","@id";
const "declaration", "substring-after($full_decl,'HMI:')";
const "_args", "substring-before($declaration,'@')";
const "args" choose {
when "$_args" value "$_args";
otherwise value "$declaration";
}
const "_typefreq", "substring-before($args,':')";
const "typefreq" choose {
when "$_typefreq" value "$_typefreq";
otherwise value "$args";
}
const "freq", "substring-after($typefreq,'|')";
const "_type", "substring-before($typefreq,'|')";
const "type" choose {
when "$_type" value "$_type";
otherwise value "$typefreq";
}
if "$type" widget {
attrib "id" > «$id»
attrib "type" > «$type»
if "$freq" {
if "not(regexp:test($freq,'^[0-9]*(\.[0-9]+)?[smh]?'))" {
error > Widget id:«$id» label:«$full_decl» has wrong syntax of frequency forcing «$freq»
}
attrib "freq" > «$freq»
}
// find "#" + JS expr at the end
const "tail", "substring-after($declaration,'@')";
const "taillen","string-length($tail)";
const "has_enable", "contains($tail, '#')";
const "paths" choose{
when "$has_enable" {
value "substring-before($tail,'#')";
}
otherwise value "$tail";
}
if "$has_enable" {
const "enable_expr", "substring-after($tail,'#')";
attrib "enable_expr" value "$enable_expr";
}
foreach "str:split(substring-after($args, ':'), ':')" {
arg {
attrib "value" > «.»
}
}
// for stricter syntax checking, this should make error
// if $paths contains "@@" or ends with "@" (empty paths)
foreach "str:split($paths, '@')" {
if "string-length(.) > 0" path {
// 1 : global match
// 2 : assign=
// 2 : /path
// 3 : min,max
const "path_match", "regexp:match(.,$pathregex)";
const "pathassign", "substring-before($path_match[2],'=')";
const "pathminmax", "str:split($path_match[4],',')";
const "path", "$path_match[3]";
const "pathminmaxcount", "count($pathminmax)";
if "not($path)"
error > Widget id:«$id» label:«$full_decl» has wrong syntax
attrib "value" value "$path";
if "$pathassign"
attrib "assign" value "$pathassign";
choose {
when "$pathminmaxcount = 2" {
attrib "min" > «$pathminmax[1]»
attrib "max" > «$pathminmax[2]»
}
when "$pathminmaxcount = 1 or $pathminmaxcount > 2" {
error > Widget id:«$id» label:«$full_decl» has wrong syntax of path section «$pathminmax»
}
}
if "$indexed_hmitree" choose {
when "regexp:test($path,'^\.[a-zA-Z0-9_]+$')" {
attrib "type" > PAGE_LOCAL
}
when "regexp:test($path,'^[a-zA-Z0-9_]+$')" {
attrib "type" > HMI_LOCAL
}
otherwise {
const "item", "$indexed_hmitree/*[@hmipath = $path]";
const "pathtype", "local-name($item)";
if "$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')" {
error > Widget id:«$id» label:«$full_decl» path section «$pathminmax» use min and max on non mumeric value
}
if "count($item) = 1" {
attrib "index" > «$item/@index»
attrib "type" > «$pathtype»
}
}
}
}
}
choose{
when "$has_continuation" {
const "_continuation", "substring-after($desc, $twonewlines)";
if "$_continuation"
desc value "$_continuation";
}
otherwise
if "$desc" desc value "$desc/text()";
}
}
}
// Templates to generate label back from parsed tree
template "arg", mode="genlabel" > :«@value»
template "path", mode="genlabel" {
> @«@value»
if "string-length(@min)>0 or string-length(@max)>0" > ,«@min»,«@max»
}
template "widget", mode="genlabel" {
> HMI:«@type»
apply "arg", mode="genlabel";
apply "path", mode="genlabel";
}