Formatter.cpp 2.9 KB

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