diff --git a/include/wex/stc/bind.h b/include/wex/stc/bind.h index 0625b7c6f..de4d453bb 100644 --- a/include/wex/stc/bind.h +++ b/include/wex/stc/bind.h @@ -2,7 +2,7 @@ // Name: bind.h // Purpose: Declaration of bind id's // Author: Anton van Wezenbeek -// Copyright: (c) 2020-2022 Anton van Wezenbeek +// Copyright: (c) 2020-2024 Anton van Wezenbeek //////////////////////////////////////////////////////////////////////////////// #pragma once @@ -14,6 +14,8 @@ namespace wex::id enum stc { beautify = wxID_HIGHEST + 1, + diff_next, + diff_previous, edge_clear, edge_set, eol_dos, diff --git a/include/wex/stc/stc.h b/include/wex/stc/stc.h index deae5365e..de7f6def4 100644 --- a/include/wex/stc/stc.h +++ b/include/wex/stc/stc.h @@ -14,10 +14,10 @@ #include #include #include +#include #include #include -#include #include namespace wex @@ -105,17 +105,11 @@ class stc : public syntax::stc /// Returns associated data. const auto& data() const { return m_data; } - /// Adds a diff line. - void diff_add(int line) { m_lines_diff.insert(line); }; + /// Returns diffs. + const unified_diffs& diffs() const { return m_diffs; }; - /// Goto first diff line. - bool diff_first(); - - /// Goto next diff line. - bool diff_next(); - - /// Goto previous diff line. - bool diff_previous(); + /// Returns writable diffs. + unified_diffs& diffs() { return m_diffs; }; /// Shows a menu with current line type checked, /// and allows you to change it. @@ -313,12 +307,10 @@ class stc : public syntax::stc function_repeat m_function_repeat; data::stc m_data; stc_file m_file; + unified_diffs m_diffs; int m_selection_mode_copy{wxSTC_SEL_STREAM}; - std::set m_lines_diff; - std::set::iterator m_lines_diff_it; - // The ex or vi component. vi* m_vi{nullptr}; diff --git a/include/wex/vcs/unified-diff.h b/include/wex/vcs/unified-diff.h index 3fe85076a..4d175c704 100644 --- a/include/wex/vcs/unified-diff.h +++ b/include/wex/vcs/unified-diff.h @@ -43,6 +43,9 @@ class unified_diff /// Provide frame, that will receive the unified diff callbacks. factory::frame* f); + /// Returns true if this is the first diff. + bool is_first() const { return m_is_first; }; + /// Parses the input. /// This routine might invoke callback methods on wex::frame. /// Returns number of differences present. @@ -84,6 +87,8 @@ class unified_diff path m_path_vcs; + bool m_is_first{true}; + const vcs_entry* m_vcs_entry{nullptr}; factory::frame* m_frame{nullptr}; diff --git a/include/wex/vcs/unified-diffs.h b/include/wex/vcs/unified-diffs.h new file mode 100644 index 000000000..e4b37e776 --- /dev/null +++ b/include/wex/vcs/unified-diffs.h @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: unified-diffs.h +// Purpose: Declaration of class unified_diffs +// Author: Anton van Wezenbeek +// Copyright: (c) 2024 Anton van Wezenbeek +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +namespace wex +{ +class stc; +class unified_diff; + +/// Offers a class that collects unified diff invocations to be able +/// to iterate through the differences and show them on stc component. +class unified_diffs +{ +public: + /// Constructor, provide stc. + unified_diffs(stc* s); + + /// Clears all differences, reset iterator. + void clear(); + + /// Returns distance of the iterator to begin of collection. + int distance() const; + + /// Goto first diff line on stc. + bool first(); + + /// Inserts a unified diff. + void insert(const unified_diff* diff); + + /// Goto next diff line on stc. If at end, goes to next stc. + bool next(); + + /// Goto previous diff line on stc. If at begin, goes to previous stc. + bool prev(); + + /// Returns number of differences present. + int size() const { return m_lines.size(); } + +private: + stc* m_stc{nullptr}; + + std::set m_lines; + std::set::iterator m_lines_it; +}; +}; // namespace wex diff --git a/src/del/frame.cpp b/src/del/frame.cpp index 1fa57cee7..ec010e9ab 100644 --- a/src/del/frame.cpp +++ b/src/del/frame.cpp @@ -940,8 +940,6 @@ bool wex::del::frame::vcs_unified_diff( diff->range_from_start() - 1, get_some_text(diff->text_removed())); } - - stc->diff_add(diff->range_from_start() - 1); } if (diff->range_to_count() > 0) @@ -955,11 +953,15 @@ bool wex::del::frame::vcs_unified_diff( log("vcs_unified_diff") << diff->path_vcs().string(); return false; } + } - stc->diff_add(diff->range_to_start() - 1); + if (diff->is_first()) + { + stc->diffs().clear(); } - stc->diff_first(); + stc->diffs().insert(diff); + stc->diffs().first(); } return true; diff --git a/src/stc/bind.cpp b/src/stc/bind.cpp index 7c22af756..06b01ac0e 100644 --- a/src/stc/bind.cpp +++ b/src/stc/bind.cpp @@ -139,8 +139,8 @@ void wex::stc::bind_all() {wxACCEL_CTRL, WXK_INSERT, wxID_COPY}, {wxACCEL_NORMAL, WXK_F3, ID_EDIT_FIND_NEXT}, {wxACCEL_NORMAL, WXK_F4, ID_EDIT_FIND_PREVIOUS}, - {wxACCEL_NORMAL, WXK_F7, wxID_SORT_ASCENDING}, - {wxACCEL_NORMAL, WXK_F8, wxID_SORT_DESCENDING}, + {wxACCEL_NORMAL, WXK_F7, id::stc::diff_next}, + {wxACCEL_NORMAL, WXK_F8, id::stc::diff_previous}, {wxACCEL_NORMAL, WXK_F9, id::stc::fold_all}, {wxACCEL_NORMAL, WXK_F10, id::stc::unfold_all}, {wxACCEL_NORMAL, WXK_F11, id::stc::uppercase}, @@ -359,6 +359,20 @@ void wex::stc::bind_all() }, ID_EDIT_FIND_PREVIOUS}, + {[=, this](const wxCommandEvent& event) + { + m_diffs.next(); + log::status("diff") << m_diffs.distance() << "from" << m_diffs.size(); + }, + id::stc::diff_next}, + + {[=, this](const wxCommandEvent& event) + { + m_diffs.prev(); + log::status("diff") << m_diffs.distance() << "from" << m_diffs.size(); + }, + id::stc::diff_previous}, + {[=, this](const wxCommandEvent& event) { link_open(link_t().set(LINK_OPEN_MIME)); diff --git a/src/stc/stc.cpp b/src/stc/stc.cpp index 8046b7a05..265f4c8f8 100644 --- a/src/stc/stc.cpp +++ b/src/stc/stc.cpp @@ -36,6 +36,7 @@ wex::stc::stc(const wex::path& p, const data::stc& data) , m_file(this, wex::path(data.window().name())) , m_hexmode(hexmode(this)) , m_frame(dynamic_cast(wxTheApp->GetTopWindow())) + , m_diffs(this) , m_function_repeat( "stc", this, @@ -246,29 +247,6 @@ void wex::stc::Cut() } } -bool wex::stc::diff_first() -{ - if (m_lines_diff.empty()) - { - return false; - } - - m_lines_diff_it = m_lines_diff.begin(); - goto_line(*m_lines_diff_it); - - return true; -} - -bool wex::stc::diff_next() -{ - return true; -} - -bool wex::stc::diff_previous() -{ - return true; -} - bool wex::stc::file_readonly_attribute_changed() { SetReadOnly(path().is_readonly()); // does not return anything diff --git a/src/vcs/unified-diff.cpp b/src/vcs/unified-diff.cpp index 16b1fcea6..d283b709d 100644 --- a/src/vcs/unified-diff.cpp +++ b/src/vcs/unified-diff.cpp @@ -137,6 +137,8 @@ std::optional wex::unified_diff::parse() } } + m_is_first = false; + if (++tok_iter != tokens.end() && !(*tok_iter).starts_with("@@")) { break; // this was last chunk, continue with header lines diff --git a/src/vcs/unified-diffs.cpp b/src/vcs/unified-diffs.cpp new file mode 100644 index 000000000..1cb09908f --- /dev/null +++ b/src/vcs/unified-diffs.cpp @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: unified-diffs.cpp +// Purpose: Implementation of class unified_diffs +// Author: Anton van Wezenbeek +// Copyright: (c) 2024 Anton van Wezenbeek +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +wex::unified_diffs::unified_diffs(stc* s) + : m_stc(s) + , m_lines_it(m_lines.begin()) +{ +} + +void wex::unified_diffs::clear() +{ + m_lines.clear(); + m_lines_it = m_lines.begin(); +} + +int wex::unified_diffs::distance() const +{ + return std::distance(m_lines.begin(), m_lines_it); +} + +bool wex::unified_diffs::first() +{ + if (m_lines.empty()) + { + return false; + } + + m_lines_it = m_lines.begin(); + + m_stc->goto_line(*m_lines_it); + + return true; +} + +void wex::unified_diffs::insert(const unified_diff* diff) +{ + if (diff->range_from_start() != 0) + { + m_lines.insert(diff->range_from_start() - 1); + } + + if (diff->range_to_start() != 0) + { + m_lines.insert(diff->range_to_start() - 1); + } + + m_lines_it = m_lines.begin(); +} + +bool wex::unified_diffs::next() +{ + if (m_lines_it == m_lines.end() || + m_lines_it == std::prev(m_lines.end())) + { + return m_stc->get_vi().command(":n"); + } + + m_lines_it++; + + m_stc->goto_line(*m_lines_it); + + return true; +} + +bool wex::unified_diffs::prev() +{ + if (m_lines_it == m_lines.begin()) + { + return m_stc->get_vi().command(":prev"); + } + + m_lines_it--; + + m_stc->goto_line(*m_lines_it); + + return true; +} diff --git a/test/vcs/test-unified-diff.cpp b/test/vcs/test-unified-diff.cpp index 5ae25844d..203c769e0 100644 --- a/test/vcs/test-unified-diff.cpp +++ b/test/vcs/test-unified-diff.cpp @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -// Name: test-vcs-entry.cpp +// Name: test-unified-diff.cpp // Purpose: Implementation for wex unit testing // Author: Anton van Wezenbeek // Copyright: (c) 2024 Anton van Wezenbeek @@ -61,6 +61,7 @@ TEST_CASE("wex::unified_diff") "@@ -38,0 +37 @@ The format is based on [Keep a Changelog].\n" "+- test\n"); + REQUIRE(uni.is_first()); const auto res(uni.parse()); REQUIRE(res); REQUIRE(*res == 4); @@ -72,6 +73,7 @@ TEST_CASE("wex::unified_diff") REQUIRE(uni.range_to_count() == 1); REQUIRE(uni.text_added().front() == "- test"); REQUIRE(uni.text_removed().empty()); + REQUIRE(!uni.is_first()); } SUBCASE("parse-valid-other") diff --git a/test/vcs/test-unified-diffs.cpp b/test/vcs/test-unified-diffs.cpp new file mode 100644 index 000000000..d59c6bd92 --- /dev/null +++ b/test/vcs/test-unified-diffs.cpp @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: test-unified-diffs.cpp +// Purpose: Implementation for wex unit testing +// Author: Anton van Wezenbeek +// Copyright: (c) 2024 Anton van Wezenbeek +//////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "test.h" + +TEST_CASE("wex::unified_diffs") +{ + SUBCASE("constructor") + { + wex::unified_diffs diffs(get_stc()); + + REQUIRE(diffs.size() == 0); + REQUIRE(diffs.distance() == 0); + REQUIRE(!diffs.first()); + REQUIRE(!diffs.next()); + REQUIRE(!diffs.prev()); + } + + SUBCASE("insert") + { + wex::unified_diff uni( + "diff --git a/build-gen.sh b/build-gen.sh\n" + "index 9ff921d..b429c21 100755\n" + "--- a/build-gen.sh\n" + "+++ b/build-gen.sh\n" + "@@ -20 +19,0 @@ usage()\n" + "- echo \"-D add a general cmake define\"\n" + "diff --git a/CHANGELOG.md b/CHANGELOG.md\n" + "index 26e9e8f..ed2116e 100644\n" + "--- a/CHANGELOG.md\n" + "+++ b/CHANGELOG.md\n" + "@@ -11 +10,0 @@ The format is based on [Keep a Changelog].\n" + "-- added git diff option\n" + "@@ -25 +23,0 @@ The format is based on [Keep a Changelog].\n" + "-- listview standard column sizes are configurable\n" + "@@ -38,0 +37 @@ The format is based on [Keep a Changelog].\n" + "+- test\n"); + + REQUIRE(uni.parse()); + + wex::unified_diffs diffs(get_stc()); + diffs.insert(&uni); + + REQUIRE(diffs.size() == 2); // only last one + REQUIRE(diffs.distance() == 0); + REQUIRE(diffs.next()); + REQUIRE(diffs.distance() == 1); + REQUIRE(!diffs.next()); // we are on the last element + REQUIRE(diffs.prev()); + REQUIRE(!diffs.prev()); + + diffs.insert(&uni); // same result + REQUIRE(diffs.size() == 2); + + diffs.clear(); + REQUIRE(diffs.size() == 0); + REQUIRE(!diffs.next()); + REQUIRE(!diffs.prev()); + } +}