/* * Copyright (c) 2020, Itamar S. * Copyright (c) 2023, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #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; }; ErrorOr> parse_hunks(StringView diff); HunkLocation parse_hunk_location(StringView location_line); }; 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(" @@"); } };