GMLFormatter.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/JsonObject.h>
  7. #include <AK/JsonValue.h>
  8. #include <AK/StringBuilder.h>
  9. #include <LibGUI/GMLFormatter.h>
  10. #include <LibGUI/GMLParser.h>
  11. namespace GUI {
  12. static String format_gml_object(const JsonObject& node, size_t indentation = 0, bool is_inline = false)
  13. {
  14. StringBuilder builder;
  15. auto indent = [&builder](size_t indentation) {
  16. for (size_t i = 0; i < indentation; ++i)
  17. builder.append(" ");
  18. };
  19. struct Property {
  20. String key;
  21. JsonValue value;
  22. };
  23. Vector<Property> properties;
  24. node.for_each_member([&](auto& key, auto& value) {
  25. if (key != "class" && key != "layout" && key != "children")
  26. properties.append({ key, value });
  27. return IterationDecision::Continue;
  28. });
  29. if (!is_inline)
  30. indent(indentation);
  31. builder.append('@');
  32. builder.append(node.get("class").as_string());
  33. builder.append(" {\n");
  34. for (auto& property : properties) {
  35. indent(indentation + 1);
  36. builder.append(property.key);
  37. builder.append(": ");
  38. if (property.value.is_array()) {
  39. // custom array serialization as AK's doesn't pretty-print
  40. // objects and arrays (we only care about arrays (for now))
  41. builder.append("[");
  42. auto first = true;
  43. property.value.as_array().for_each([&](auto& value) {
  44. if (!first)
  45. builder.append(", ");
  46. first = false;
  47. value.serialize(builder);
  48. });
  49. builder.append("]");
  50. } else {
  51. property.value.serialize(builder);
  52. }
  53. builder.append("\n");
  54. }
  55. if (node.has("layout")) {
  56. auto layout = node.get("layout").as_object();
  57. if (!properties.is_empty())
  58. builder.append("\n");
  59. indent(indentation + 1);
  60. builder.append("layout: ");
  61. builder.append(format_gml_object(move(layout), indentation + 1, true));
  62. }
  63. if (node.has("children")) {
  64. auto children = node.get("children").as_array();
  65. auto first = properties.is_empty() && !node.has("layout");
  66. children.for_each([&](auto& value) {
  67. if (!first)
  68. builder.append("\n");
  69. first = false;
  70. builder.append(format_gml_object(value.as_object(), indentation + 1));
  71. });
  72. }
  73. indent(indentation);
  74. builder.append("}\n");
  75. return builder.to_string();
  76. }
  77. String format_gml(const StringView& string)
  78. {
  79. // FIXME: Preserve comments somehow, they're not contained
  80. // in the JSON object returned by parse_gml()
  81. auto ast = parse_gml(string);
  82. if (ast.is_null())
  83. return {};
  84. VERIFY(ast.is_object());
  85. return format_gml_object(ast.as_object());
  86. }
  87. }