diff --git a/doc/en/scripting/builtins/libutf8.md b/doc/en/scripting/builtins/libutf8.md
index bd8dd22b..c8837c65 100644
--- a/doc/en/scripting/builtins/libutf8.md
+++ b/doc/en/scripting/builtins/libutf8.md
@@ -30,4 +30,7 @@ utf8.lower(text: str) -> str
-- Escapes a string
utf8.escape(text: str) -> str
+
+-- Escapes special XML characters
+utf8.escape_xml(text: str) -> str
```
diff --git a/doc/ru/scripting/builtins/libutf8.md b/doc/ru/scripting/builtins/libutf8.md
index ce933417..e4d79f4f 100644
--- a/doc/ru/scripting/builtins/libutf8.md
+++ b/doc/ru/scripting/builtins/libutf8.md
@@ -30,4 +30,7 @@ utf8.lower(text: str) -> str
-- Экранирует строку
utf8.escape(text: str) -> str
+
+-- Экранирует спец-символы XML
+utf8.escape_xml(text: str) -> str
```
diff --git a/doc/ru/scripting/extensions.md b/doc/ru/scripting/extensions.md
index 2d7f0a1d..9a89b2b5 100644
--- a/doc/ru/scripting/extensions.md
+++ b/doc/ru/scripting/extensions.md
@@ -187,6 +187,12 @@ string.escape(str: string) -> string
Экранирует строку. Является псевдонимом `utf8.escape`.
+```lua
+string.escape_xml(text: str) -> str
+```
+
+Экранирует спец-символы XML. Является псевдонимом `utf8.escape_xml`.
+
```lua
string.pad(str: string, size: number, [опционально] char: string) -> string
```
diff --git a/res/devtools/default_syntax_scheme.toml b/res/devtools/default_syntax_scheme.toml
new file mode 100644
index 00000000..885defd6
--- /dev/null
+++ b/res/devtools/default_syntax_scheme.toml
@@ -0,0 +1,19 @@
+[default]
+bold = false
+italic = false
+strikethrough = false
+underline = false
+color = [0.8, 0.8, 0.8, 1]
+
+[keyword]
+bold = true
+color = [0.9, 0.6, 0.4, 1]
+
+[literal]
+color = [0.4, 0.8, 0.5, 1]
+
+[comment]
+color = [0.5, 0.7, 1.0, 1]
+
+[error]
+color = [1.0, 0.2, 0.1, 1]
diff --git a/res/modules/internal/extensions/string.lua b/res/modules/internal/extensions/string.lua
index f76470df..313ae57b 100644
--- a/res/modules/internal/extensions/string.lua
+++ b/res/modules/internal/extensions/string.lua
@@ -105,6 +105,7 @@ end
string.lower = utf8.lower
string.upper = utf8.upper
string.escape = utf8.escape
+string.escape_xml = utf8.escape_xml
local meta = getmetatable("")
diff --git a/res/modules/internal/gui_util.lua b/res/modules/internal/gui_util.lua
index 15360521..4766cbfd 100644
--- a/res/modules/internal/gui_util.lua
+++ b/res/modules/internal/gui_util.lua
@@ -3,8 +3,8 @@ local gui_util = {
}
--- Parse `pagename?arg1=value1&arg2=value2` queries
---- @param query page query string
---- @return page_name, args_table
+--- @param query string page query string
+--- @return string, string -> page_name, args_table
function gui_util.parse_query(query)
local args = {}
local name
@@ -23,8 +23,7 @@ function gui_util.parse_query(query)
return name, args
end
---- @param query page query string
---- @return document_id
+--- @param query string page query string
function gui_util.load_page(query)
local name, args = gui_util.parse_query(query)
for i = #gui_util.local_dispatchers, 1, -1 do
@@ -116,4 +115,52 @@ gui_util.Document = Document
gui_util.Element = Element
gui_util.RadioGroup = RadioGroup
+function gui.show_message(text, actual_callback)
+ local id = "dialog_"..random.uuid()
+
+ local callback = function()
+ gui.root[id]:destruct()
+ if actual_callback then
+ actual_callback()
+ end
+ end
+ gui.root.root:add(string.format([[
+
+
+
+
+
+
+ ]], id, string.escape_xml(text)), {callback=callback})
+ input.add_callback("key:escape", callback, gui.root[id])
+end
+
+function gui.ask(text, on_yes, on_no)
+ on_yes = on_yes or function() end
+ on_no = on_no or function() end
+
+ local id = "dialog_"..random.uuid()
+
+ local yes_callback = function()
+ gui.root[id]:destruct()
+ on_yes()
+ end
+ local no_callback = function()
+ gui.root[id]:destruct()
+ on_no()
+ end
+ gui.root.root:add(string.format([[
+
+
+
+
+
+
+
+ ]], id, string.escape_xml(text)), {on_yes=yes_callback, on_no=no_callback})
+ input.add_callback("key:escape", no_callback, gui.root[id])
+end
+
return gui_util
diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua
index 571bf32f..dcca0f28 100644
--- a/res/scripts/stdlib.lua
+++ b/res/scripts/stdlib.lua
@@ -150,6 +150,18 @@ _MENU = _GUI_ROOT.menu
menu = _MENU
gui.root = _GUI_ROOT
+do
+ local status, err = pcall(function()
+ local default_styles = toml.parse(file.read(
+ "res:devtools/default_syntax_scheme.toml"
+ ))
+ gui.set_syntax_styles(default_styles)
+ end)
+ if not status then
+ debug.error("could not to load default syntax scheme: "..err)
+ end
+end
+
--- Console library extension ---
console.cheats = {}
diff --git a/src/devtools/SyntaxProcessor.cpp b/src/devtools/SyntaxProcessor.cpp
index a4a1c7cf..c1c3f179 100644
--- a/src/devtools/SyntaxProcessor.cpp
+++ b/src/devtools/SyntaxProcessor.cpp
@@ -7,19 +7,15 @@
using namespace devtools;
static std::unique_ptr build_styles(
+ const FontStylesScheme& colorScheme,
const std::vector& tokens
) {
using devtools::TokenTag;
- FontStylesScheme styles {
- {
- {false, false, false, false, glm::vec4(0.8f, 0.8f, 0.8f, 1)}, // default
- {true, false, false, false, glm::vec4(0.9, 0.6f, 0.4f, 1)}, // keyword
- {false, false, false, false, glm::vec4(0.4, 0.8f, 0.5f, 1)}, // string
- {false, false, false, false, glm::vec4(0.3, 0.3f, 0.3f, 1)}, // comment
- {true, false, false, false, glm::vec4(1.0f, 0.2f, 0.1f, 1)}, // unexpected
- },
- {}
- };
+ FontStylesScheme styles {colorScheme.palette, {}};
+ if (styles.palette.empty()) {
+ styles.palette.push_back(FontStyle {
+ false, false, false, false, glm::vec4(0.8f, 0.8f, 0.8f, 1)});
+ }
size_t offset = 0;
for (int i = 0; i < tokens.size(); i++) {
const auto& token = tokens.at(i);
@@ -47,6 +43,9 @@ static std::unique_ptr build_styles(
styleIndex = 0;
break;
}
+ if (styleIndex >= styles.palette.size()) {
+ styleIndex = 0;
+ }
styles.map.insert(
styles.map.end(), token.end.pos - token.start.pos, styleIndex
);
@@ -67,7 +66,9 @@ void SyntaxProcessor::addSyntax(
}
std::unique_ptr SyntaxProcessor::highlight(
- const std::string& ext, std::wstring_view source
+ const FontStylesScheme& colorScheme,
+ const std::string& ext,
+ std::wstring_view source
) const {
const auto& found = langsExtensions.find(ext);
if (found == langsExtensions.end()) {
@@ -76,7 +77,7 @@ std::unique_ptr SyntaxProcessor::highlight(
const auto& syntax = *found->second;
try {
auto tokens = tokenize(syntax, "", source);
- return build_styles(tokens);
+ return build_styles(colorScheme, tokens);
} catch (const parsing_error& err) {
return nullptr;
}
diff --git a/src/devtools/SyntaxProcessor.hpp b/src/devtools/SyntaxProcessor.hpp
index afb975a8..d0ae41e7 100644
--- a/src/devtools/SyntaxProcessor.hpp
+++ b/src/devtools/SyntaxProcessor.hpp
@@ -18,7 +18,9 @@ namespace devtools {
class SyntaxProcessor {
public:
std::unique_ptr highlight(
- const std::string& ext, std::wstring_view source
+ const FontStylesScheme& colorScheme,
+ const std::string& ext,
+ std::wstring_view source
) const;
void addSyntax(std::unique_ptr syntax);
diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp
index 3e9a3a27..da4fec51 100644
--- a/src/frontend/UiDocument.cpp
+++ b/src/frontend/UiDocument.cpp
@@ -23,11 +23,12 @@ void UiDocument::rebuildIndices() {
map["root"] = root;
}
-const UINodesMap& UiDocument::getMap() const {
- return map;
+void UiDocument::pushIndices(const std::shared_ptr& node) {
+ gui::UINode::getIndices(node, map);
+ map["root"] = root;
}
-UINodesMap& UiDocument::getMapWriteable() {
+const UINodesMap& UiDocument::getMap() const {
return map;
}
diff --git a/src/frontend/UiDocument.hpp b/src/frontend/UiDocument.hpp
index 9d6e6eca..2ad00da8 100644
--- a/src/frontend/UiDocument.hpp
+++ b/src/frontend/UiDocument.hpp
@@ -36,10 +36,10 @@ public:
);
void rebuildIndices();
+ void pushIndices(const std::shared_ptr& node);
const std::string& getId() const;
const UINodesMap& getMap() const;
- UINodesMap& getMapWriteable();
std::shared_ptr getRoot() const;
std::shared_ptr get(const std::string& id) const;
const uidocscript& getScript() const;
diff --git a/src/graphics/commons/FontStyle.cpp b/src/graphics/commons/FontStyle.cpp
new file mode 100644
index 00000000..53cc0657
--- /dev/null
+++ b/src/graphics/commons/FontStyle.cpp
@@ -0,0 +1,37 @@
+#include "FontStyle.hpp"
+
+#include "data/dv.hpp"
+#include "data/dv_util.hpp"
+#include "devtools/SyntaxProcessor.hpp"
+
+FontStyle FontStyle::parse(const dv::value& src) {
+ FontStyle style {};
+ src.at("bold").get(style.bold);
+ src.at("italic").get(style.italic);
+ src.at("strikethrough").get(style.strikethrough);
+ src.at("underline").get(style.underline);
+ dv::get_vec(src, "color", style.color);
+ return style;
+}
+
+static void parse_style(
+ const dv::value& src,
+ FontStylesScheme& scheme,
+ const std::string& name,
+ devtools::SyntaxStyles tag
+) {
+ if (src.has(name)) {
+ scheme.palette[static_cast(tag)] = FontStyle::parse(src[name]);
+ }
+}
+
+FontStylesScheme FontStylesScheme::parse(const dv::value& src) {
+ FontStylesScheme scheme {};
+ scheme.palette.resize(8);
+ parse_style(src, scheme, "default", devtools::SyntaxStyles::DEFAULT);
+ parse_style(src, scheme, "keyword", devtools::SyntaxStyles::KEYWORD);
+ parse_style(src, scheme, "literal", devtools::SyntaxStyles::LITERAL);
+ parse_style(src, scheme, "comment", devtools::SyntaxStyles::COMMENT);
+ parse_style(src, scheme, "error", devtools::SyntaxStyles::ERROR);
+ return scheme;
+}
diff --git a/src/graphics/commons/FontStyle.hpp b/src/graphics/commons/FontStyle.hpp
new file mode 100644
index 00000000..5f0129f9
--- /dev/null
+++ b/src/graphics/commons/FontStyle.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "data/dv_fwd.hpp"
+
+#include
+#include
+
+struct FontStyle {
+ bool bold = false;
+ bool italic = false;
+ bool strikethrough = false;
+ bool underline = false;
+ glm::vec4 color {1, 1, 1, 1};
+
+ FontStyle() = default;
+
+ FontStyle(
+ bool bold,
+ bool italic,
+ bool strikethrough,
+ bool underline,
+ glm::vec4 color
+ )
+ : bold(bold),
+ italic(italic),
+ strikethrough(strikethrough),
+ underline(underline),
+ color(std::move(color)) {
+ }
+
+ static FontStyle parse(const dv::value& src);
+};
+
+struct FontStylesScheme {
+ std::vector palette;
+ std::vector map;
+
+ static FontStylesScheme parse(const dv::value& src);
+};
diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp
index 12371595..f30335be 100644
--- a/src/graphics/core/Font.hpp
+++ b/src/graphics/core/Font.hpp
@@ -7,41 +7,14 @@
#include "typedefs.hpp"
#include "FontMetics.hpp"
+#include "data/dv_fwd.hpp"
+#include "../commons/FontStyle.hpp"
class Texture;
class Batch2D;
class Batch3D;
class Camera;
-struct FontStyle {
- bool bold = false;
- bool italic = false;
- bool strikethrough = false;
- bool underline = false;
- glm::vec4 color {1, 1, 1, 1};
-
- FontStyle() = default;
-
- FontStyle(
- bool bold,
- bool italic,
- bool strikethrough,
- bool underline,
- glm::vec4 color
- )
- : bold(bold),
- italic(italic),
- strikethrough(strikethrough),
- underline(underline),
- color(std::move(color)) {
- }
-};
-
-struct FontStylesScheme {
- std::vector palette;
- std::vector map;
-};
-
class Font {
int lineHeight;
int yoffset;
diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp
index 3ab438b1..22ae5b90 100644
--- a/src/graphics/ui/GUI.cpp
+++ b/src/graphics/ui/GUI.cpp
@@ -80,6 +80,14 @@ std::shared_ptr