diff --git a/src/common.h b/src/common.h index 633570d42..d540d0996 100644 --- a/src/common.h +++ b/src/common.h @@ -379,6 +379,42 @@ wcstring_list_t split_string(const wcstring &val, wchar_t sep); /// Join a list of strings by a separator character. wcstring join_strings(const wcstring_list_t &vals, wchar_t sep); +/// Support for iterating over a newline-separated string. +template +class line_iterator_t { + // Storage for each line. + Collection storage; + + // The collection we're iterating. Note we hold this by reference. + const Collection &coll; + + // The current location in the iteration. + typename Collection::const_iterator current; + +public: + /// Construct from a collection (presumably std::string or std::wcstring). + line_iterator_t(const Collection &coll) : coll(coll), current(coll.cbegin()) {} + + /// Access the storage in which the last line was stored. + const Collection &line() const { + return storage; + } + + /// Advances to the next line. \return true on success, false if we have exhausted the string. + bool next() { + if (current == coll.end()) + return false; + auto newline_or_end = std::find(current, coll.cend(), '\n'); + storage.assign(current, newline_or_end); + current = newline_or_end; + + // Skip the newline. + if (current != coll.cend()) + ++current; + return true; + } +}; + enum fuzzy_match_type_t { // We match the string exactly: FOOBAR matches FOOBAR. fuzzy_match_exact = 0, diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 70d5938f9..cc2dbeef7 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2809,6 +2809,22 @@ static void test_input() { } } +static void test_line_iterator() { + say(L"Testing line iterator"); + + std::string text1 = "Alpha\nBeta\nGamma\n\nDelta\n"; + std::vector lines1; + line_iterator_t iter1(text1); + while (iter1.next()) lines1.push_back(iter1.line()); + do_test((lines1 == std::vector{"Alpha", "Beta", "Gamma", "", "Delta"})); + + wcstring text2 = L"\n\nAlpha\nBeta\nGamma\n\nDelta"; + std::vector lines2; + line_iterator_t iter2(text2); + while (iter2.next()) lines2.push_back(iter2.line()); + do_test((lines2 == std::vector{L"", L"", L"Alpha", L"Beta", L"Gamma", L"", L"Delta"})); +} + #define UVARS_PER_THREAD 8 #define UVARS_TEST_PATH L"test/fish_uvars_test/varsfile.txt" @@ -4805,6 +4821,7 @@ int main(int argc, char **argv) { if (should_test_function("colors")) test_colors(); if (should_test_function("complete")) test_complete(); if (should_test_function("input")) test_input(); + if (should_test_function("line_iterator")) test_line_iterator(); if (should_test_function("universal")) test_universal(); if (should_test_function("universal")) test_universal_callbacks(); if (should_test_function("notifiers")) test_universal_notifiers();