diff --git a/doc/settings.md b/doc/settings.md
index f350cb0f76..734a83a769 100644
--- a/doc/settings.md
+++ b/doc/settings.md
@@ -65,6 +65,8 @@ The file list is built in the following order from the following sources:
- `name=2000` and `name="2000"` have the same meaning.
- There is no distinction between XML-attribute and XML-subobject, i.e. any attributes are sub-objects:
- `` and ` ` have the same meaning.
+ - No spaces are allowed between the opening angle bracket and the name when declaring an XML-subobject.
+ - `... < name ...`, `... <= ...`, `... << ...` are treated as parts of Lua script code.
- In addition to a set of sub-objects each object can contain its own text value:
- E.g. `` - subobject `name` has text value `names_value`.
- Each object can be defined in any way, either using an XML-attribute or an XML-subobject syntax:
diff --git a/src/netxs/desktopio/application.hpp b/src/netxs/desktopio/application.hpp
index d3acf48c54..2421d3a101 100644
--- a/src/netxs/desktopio/application.hpp
+++ b/src/netxs/desktopio/application.hpp
@@ -22,7 +22,7 @@ namespace netxs::app
namespace netxs::app::shared
{
- static const auto version = "v2025.05.21";
+ static const auto version = "v2025.05.21a";
static const auto repository = "https://github.com/directvt/vtm";
static const auto usr_config = "~/.config/vtm/settings.xml"s;
static const auto sys_config = "/etc/vtm/settings.xml"s;
diff --git a/src/netxs/desktopio/utf.hpp b/src/netxs/desktopio/utf.hpp
index 73bb31f94b..c79382230d 100644
--- a/src/netxs/desktopio/utf.hpp
+++ b/src/netxs/desktopio/utf.hpp
@@ -1709,8 +1709,17 @@ namespace netxs::utf
debase437(utf8, buff);
return buff;
}
- // utf: Find char position ignoring backslashed.
+ // utf: Find char position.
auto _find_char(auto head, auto tail, auto hittest)
+ {
+ while (head != tail && !hittest(head))
+ {
+ ++head;
+ }
+ return head;
+ }
+ // utf: Find char position ignoring backslashed.
+ auto _find_char_except_escaped(auto head, auto tail, auto hittest)
{
while (head != tail)
{
@@ -1723,20 +1732,60 @@ namespace netxs::utf
template
auto find_char(Iter head, Iter tail, view delims)
{
- return _find_char(head, tail, [&](auto iter){ return delims.find(*iter) != view::npos; });
+ return _find_char_except_escaped(head, tail, [&](auto iter){ return delims.find(*iter) != view::npos; });
+ }
+ // utf: Check if utf8 start with test string.
+ bool _starts_with(auto& iter, view utf8, view test)
+ {
+ auto found = utf8.starts_with(test);
+ if (found)
+ {
+ iter += test.size();
+ }
+ return found;
+ }
+ // utf: Check if utf8 starts with something using test proc (the test proc must do increment of iter if skips).
+ bool _starts_with(auto& iter, view utf8, auto test)
+ {
+ return test(iter, utf8);
+ }
+ // utf: Find char position ignoring skips.
+ template
+ auto find_char_except_skips(view utf8, char c, Args&&... skips)
+ {
+ auto head = utf8.begin();
+ auto tail = utf8.end();
+ auto found_iter = _find_char(head, tail, [&](auto& iter)
+ {
+ if (*iter == c)
+ {
+ auto substr = view{ iter, tail };
+ auto found = (utf::_starts_with(iter, substr, skips) || ...);
+ if (found)
+ {
+ return iter == tail; // faux if not end
+ }
+ else
+ {
+ return true;
+ }
+ }
+ return faux;
+ });
+ return found_iter;
}
// utf: Find substring position ignoring backslashed.
auto find_substring(view& utf8, auto... delims)
{
auto head = utf8.begin();
auto tail = utf8.end();
- return _find_char(head, tail, [&](auto iter){ return (view{ iter, tail }.starts_with(delims) || ...); });
+ return _find_char_except_escaped(head, tail, [&](auto iter){ return (view{ iter, tail }.starts_with(delims) || ...); });
}
// utf: Find char position ignoring backslashed.
template
auto find_char(Iter head, Iter tail, char delim)
{
- return _find_char(head, tail, [&](auto iter){ return *iter == delim; });
+ return _find_char_except_escaped(head, tail, [&](auto iter){ return *iter == delim; });
}
auto check_any(view shadow, view delims)
{
diff --git a/src/netxs/desktopio/xml.hpp b/src/netxs/desktopio/xml.hpp
index 3bdad897da..93da36578c 100644
--- a/src/netxs/desktopio/xml.hpp
+++ b/src/netxs/desktopio/xml.hpp
@@ -239,7 +239,10 @@ namespace netxs::xml
close_inline, // '>' ex: ... >
empty_tag, // '/>' ex: ... />
equal, // '=' ex: name=value
- defaults, // '*' ex: name*
+ defaults, //todo deprecate '*' ex: name*
+ lua_op_shl, // '<<' ex: Lua's shift left operator
+ lua_op_less, // '< ' ex: Lua's less than operator
+ lua_op_less_eq,// '<=' ex: Lua's less than or equal operator
compact, // '/[^>]' ex: compact syntax:
include, // ':' ex:
localpath, // ex:
@@ -651,19 +654,22 @@ namespace netxs::xml
}
};
- static constexpr auto find_start = "<"sv;
- static constexpr auto rawtext_delims = std::tuple{ " "sv, "/>"sv, ">"sv, "<"sv, "\n"sv, "\r"sv, "\t"sv };
- static constexpr auto token_delims = " \t\n\r=*/><"sv;
- static constexpr auto view_comment_begin = ""sv;
- static constexpr auto view_close_tag = ""sv;
- static constexpr auto view_begin_tag = "<"sv;
- static constexpr auto view_empty_tag = "/>"sv;
- static constexpr auto view_slash = "/"sv;
- static constexpr auto view_close_inline = ">"sv;
- static constexpr auto view_quoted_text = "\""sv;
- static constexpr auto view_equal = "="sv;
- static constexpr auto view_defaults = "*"sv;
+ static constexpr auto find_start = "<"sv;
+ static constexpr auto rawtext_delims = std::tuple{ " "sv, "/>"sv, ">"sv, "<"sv, "\n"sv, "\r"sv, "\t"sv };
+ static constexpr auto token_delims = " \t\n\r=*/><"sv;
+ static constexpr auto view_comment_begin = ""sv;
+ static constexpr auto view_close_tag = ""sv;
+ static constexpr auto view_begin_tag = "<"sv;
+ static constexpr auto view_empty_tag = "/>"sv;
+ static constexpr auto view_slash = "/"sv;
+ static constexpr auto view_close_inline = ">"sv;
+ static constexpr auto view_quoted_text = "\""sv;
+ static constexpr auto view_equal = "="sv;
+ static constexpr auto view_defaults = "*"sv;
+ static constexpr auto view_lua_op_shl = "<<"sv;
+ static constexpr auto view_lua_op_less = "< "sv;
+ static constexpr auto view_lua_op_less_eq = "<="sv;
suit page;
sptr root;
@@ -856,22 +862,25 @@ namespace netxs::xml
{
switch (what)
{
- case type::na: return view{ "{START}" } ;
- case type::eof: return view{ "{EOF}" } ;
- case type::eol: return view{ "{EOL}" } ;
- case type::token: return view{ "{token}" } ;
- case type::raw_text: return view{ "{raw text}" };
- case type::compact: return view{ "{compact}" } ;
- case type::quoted_text: return view_quoted_text ;
- case type::begin_tag: return view_begin_tag ;
- case type::close_tag: return view_close_tag ;
- case type::comment_begin: return view_comment_begin ;
- case type::comment_close: return view_comment_close ;
- case type::close_inline: return view_close_inline ;
- case type::empty_tag: return view_empty_tag ;
- case type::equal: return view_equal ;
- case type::defaults: return view_defaults ;
- default: return view{ "{unknown}" } ;
+ case type::na: return view{ "{START}" } ;
+ case type::eof: return view{ "{EOF}" } ;
+ case type::eol: return view{ "{EOL}" } ;
+ case type::token: return view{ "{token}" } ;
+ case type::raw_text: return view{ "{raw text}" } ;
+ case type::compact: return view{ "{compact}" } ;
+ case type::quoted_text: return view_quoted_text ;
+ case type::begin_tag: return view_begin_tag ;
+ case type::close_tag: return view_close_tag ;
+ case type::comment_begin: return view_comment_begin ;
+ case type::comment_close: return view_comment_close ;
+ case type::close_inline: return view_close_inline ;
+ case type::empty_tag: return view_empty_tag ;
+ case type::equal: return view_equal ;
+ case type::defaults: return view_defaults ;
+ case type::lua_op_shl: return view_lua_op_shl ;
+ case type::lua_op_less: return view_lua_op_less ;
+ case type::lua_op_less_eq: return view_lua_op_less_eq ;
+ default: return view{ "{unknown}" } ;
};
};
fail(ansi::add("Unexpected '", str(what), "' after '", str(last), "'"));
@@ -1088,8 +1097,8 @@ namespace netxs::xml
}
else if (what == type::raw_text)
{
- auto size = data.find('<');
- if (size == view::npos)
+ auto iter = utf::find_char_except_skips(data, '<', view_lua_op_shl, view_lua_op_less, view_lua_op_less_eq);
+ if (iter == data.end())
{
item->body.push_back(page.append(type::unknown, data));
data = {};
@@ -1097,6 +1106,7 @@ namespace netxs::xml
what = type::eof;
break;
}
+ auto size = iter - data.begin();
item->body.push_back(page.append(type::raw_text, data.substr(0, size)));
data.remove_prefix(size);
temp = data;
diff --git a/src/vtm.xml b/src/vtm.xml
index bfb43de897..f65317ca49 100644
--- a/src/vtm.xml
+++ b/src/vtm.xml
@@ -418,9 +418,9 @@ R"==(
+ -->
-