mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:58:11 +00:00
LibGUI: Add GMLFormatter
This will be useful for both the Playground app as well as for a standalone CLI tool (à la clang-format). It cannot handle comments yet (and will drop them from the formatted output), but other than that it produces valid GML that matches the formatting we have so far! :^)
This commit is contained in:
parent
acdbf66b54
commit
e608723031
3 changed files with 156 additions and 0 deletions
120
Libraries/LibGUI/GMLFormatter.cpp
Normal file
120
Libraries/LibGUI/GMLFormatter.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <mail@linusgroh.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibGUI/GMLFormatter.h>
|
||||
#include <LibGUI/GMLParser.h>
|
||||
|
||||
namespace GUI {
|
||||
|
||||
static String format_gml_object(const JsonObject& node, size_t indentation = 0, bool is_inline = false)
|
||||
{
|
||||
StringBuilder builder;
|
||||
|
||||
auto indent = [&builder](size_t indentation) {
|
||||
for (size_t i = 0; i < indentation; ++i)
|
||||
builder.append(" ");
|
||||
};
|
||||
|
||||
struct Property {
|
||||
String key;
|
||||
JsonValue value;
|
||||
};
|
||||
Vector<Property> properties;
|
||||
node.for_each_member([&](auto& key, auto& value) {
|
||||
if (key != "class" && key != "layout" && key != "children")
|
||||
properties.append({ key, value });
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
if (!is_inline)
|
||||
indent(indentation);
|
||||
builder.append('@');
|
||||
builder.append(node.get("class").as_string());
|
||||
builder.append(" {\n");
|
||||
|
||||
for (auto& property : properties) {
|
||||
indent(indentation + 1);
|
||||
builder.append(property.key);
|
||||
builder.append(": ");
|
||||
if (property.value.is_array()) {
|
||||
// custom array serialization as AK's doesn't pretty-print
|
||||
// objects and arrays (we only care about arrays (for now))
|
||||
builder.append("[");
|
||||
auto first = true;
|
||||
property.value.as_array().for_each([&](auto& value) {
|
||||
if (!first)
|
||||
builder.append(", ");
|
||||
first = false;
|
||||
value.serialize(builder);
|
||||
});
|
||||
builder.append("]");
|
||||
} else {
|
||||
property.value.serialize(builder);
|
||||
}
|
||||
builder.append("\n");
|
||||
}
|
||||
|
||||
if (node.has("layout")) {
|
||||
auto layout = node.get("layout").as_object();
|
||||
if (!properties.is_empty())
|
||||
builder.append("\n");
|
||||
indent(indentation + 1);
|
||||
builder.append("layout: ");
|
||||
builder.append(format_gml_object(move(layout), indentation + 1, true));
|
||||
}
|
||||
|
||||
if (node.has("children")) {
|
||||
auto children = node.get("children").as_array();
|
||||
auto first = properties.is_empty() && !node.has("layout");
|
||||
children.for_each([&](auto& value) {
|
||||
if (!first)
|
||||
builder.append("\n");
|
||||
first = false;
|
||||
builder.append(format_gml_object(value.as_object(), indentation + 1));
|
||||
});
|
||||
}
|
||||
|
||||
indent(indentation);
|
||||
builder.append("}\n");
|
||||
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
String format_gml(const StringView& string)
|
||||
{
|
||||
// FIXME: Preserve comments somehow, they're not contained
|
||||
// in the JSON object returned by parse_gml()
|
||||
auto ast = parse_gml(string);
|
||||
if (ast.is_null())
|
||||
return {};
|
||||
ASSERT(ast.is_object());
|
||||
return format_gml_object(ast.as_object());
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue