diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index d70c2e0dd8..15c76102b5 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -431,10 +431,11 @@ if (BUILD_LAGOM) # WebView list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/AccessibilityTreeModel.cpp") list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/DOMTreeModel.cpp") + list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/RequestServerAdapter.cpp") + list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/SourceHighlighter.cpp") list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/StylePropertiesModel.cpp") list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/ViewImplementation.cpp") list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/WebContentClient.cpp") - list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/RequestServerAdapter.cpp") list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/WebSocketClientAdapter.cpp") compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebContent/WebContentServer.ipc WebContent/WebContentServerEndpoint.h) diff --git a/Userland/Libraries/LibWebView/CMakeLists.txt b/Userland/Libraries/LibWebView/CMakeLists.txt index fca24a498f..835751ac43 100644 --- a/Userland/Libraries/LibWebView/CMakeLists.txt +++ b/Userland/Libraries/LibWebView/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES DOMTreeModel.cpp OutOfProcessWebView.cpp RequestServerAdapter.cpp + SourceHighlighter.cpp StylePropertiesModel.cpp ViewImplementation.cpp WebContentClient.cpp diff --git a/Userland/Libraries/LibWebView/SourceHighlighter.cpp b/Userland/Libraries/LibWebView/SourceHighlighter.cpp new file mode 100644 index 0000000000..37c22bdbcb --- /dev/null +++ b/Userland/Libraries/LibWebView/SourceHighlighter.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2023, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace WebView { + +String highlight_source(URL const& url, StringView source) +{ + Web::HTML::HTMLTokenizer tokenizer { source, "utf-8"sv }; + StringBuilder builder; + + builder.append(R"~~~( + + + + )~~~"sv); + + builder.appendff("View Source - {}", url); + + builder.append(R"~~~( + + + +
+)~~~"sv);
+
+    size_t previous_position = 0;
+
+    auto append_source = [&](auto end_position, Optional const& class_name = {}) {
+        if (end_position <= previous_position)
+            return;
+
+        auto segment = source.substring_view(previous_position, end_position - previous_position);
+
+        if (class_name.has_value())
+            builder.appendff(""sv, *class_name);
+
+        for (auto code_point : Utf8View { segment }) {
+            if (code_point == '&')
+                builder.append("&"sv);
+            else if (code_point == 0xA0)
+                builder.append(" "sv);
+            else if (code_point == '<')
+                builder.append("<"sv);
+            else if (code_point == '>')
+                builder.append(">"sv);
+            else
+                builder.append_code_point(code_point);
+        }
+
+        if (class_name.has_value())
+            builder.append(""sv);
+
+        previous_position = end_position;
+    };
+
+    for (auto token = tokenizer.next_token(); token.has_value(); token = tokenizer.next_token()) {
+        if (token->is_comment()) {
+            append_source(token->start_position().byte_offset);
+            append_source(token->end_position().byte_offset, "comment"sv);
+        } else if (token->is_start_tag() || token->is_end_tag()) {
+            auto tag_name_start = token->start_position().byte_offset;
+
+            append_source(tag_name_start);
+            append_source(tag_name_start + token->tag_name().length(), "tag"sv);
+
+            token->for_each_attribute([&](auto const& attribute) {
+                append_source(attribute.name_start_position.byte_offset);
+                append_source(attribute.name_end_position.byte_offset, "attribute-name"sv);
+
+                append_source(attribute.value_start_position.byte_offset);
+                append_source(attribute.value_end_position.byte_offset, "attribute-value"sv);
+
+                return IterationDecision::Continue;
+            });
+
+            append_source(token->end_position().byte_offset);
+        } else {
+            append_source(token->end_position().byte_offset);
+        }
+    }
+
+    builder.append(R"~~~(
+
+ + +)~~~"sv); + + return MUST(builder.to_string()); +} + +} diff --git a/Userland/Libraries/LibWebView/SourceHighlighter.h b/Userland/Libraries/LibWebView/SourceHighlighter.h new file mode 100644 index 0000000000..69345cf5c9 --- /dev/null +++ b/Userland/Libraries/LibWebView/SourceHighlighter.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace WebView { + +String highlight_source(URL const&, StringView); + +}