/* * Copyright (c) 2020, Itamar S. * Copyright (c) 2023, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include namespace Diff { struct Range { size_t start_line { 0 }; size_t number_of_lines { 0 }; }; struct HunkLocation { Range old_range; Range new_range; }; struct Line { enum class Operation { Addition = '+', Removal = '-', Context = ' ', // NOTE: This should only be used when deconstructing a hunk into old and new lines (context format) Change = '!', }; static constexpr Operation operation_from_symbol(char symbol) { switch (symbol) { case '+': return Operation::Addition; case '-': return Operation::Removal; case ' ': return Operation::Context; default: VERIFY_NOT_REACHED(); } } Operation operation; String content; }; struct Hunk { HunkLocation location; Vector lines; }; enum class Format { Unified, Unknown, }; struct Header { Format format { Format::Unknown }; String old_file_path; String new_file_path; }; struct Patch { Header header; Vector hunks; }; class Parser : public GenericLexer { public: using GenericLexer::GenericLexer; ErrorOr parse_patch(Optional const& strip_count = {}); ErrorOr> parse_hunks(); private: ErrorOr
parse_header(Optional const& strip_count); ErrorOr parse_file_line(Optional const& strip_count); Optional consume_unified_location(); bool consume_line_number(size_t& number); }; ErrorOr> parse_hunks(StringView diff); } template<> struct AK::Formatter : Formatter { ErrorOr format(FormatBuilder& builder, Diff::Line::Operation operation) { return Formatter::format(builder, "{}"sv, static_cast(operation)); } }; template<> struct AK::Formatter : Formatter { ErrorOr format(FormatBuilder& builder, Diff::Line const& line) { return Formatter::format(builder, "{}{}"sv, line.operation, line.content); } }; template<> struct AK::Formatter : Formatter { static ErrorOr format(FormatBuilder& format_builder, Diff::HunkLocation const& location) { auto& builder = format_builder.builder(); TRY(builder.try_appendff("@@ -{}"sv, location.old_range.start_line)); if (location.old_range.number_of_lines != 1) TRY(builder.try_appendff(",{}", location.old_range.number_of_lines)); TRY(builder.try_appendff(" +{}", location.new_range.start_line)); if (location.new_range.number_of_lines != 1) TRY(builder.try_appendff(",{}", location.new_range.number_of_lines)); return builder.try_appendff(" @@"); } };