From 9ec9eb1b69ea646ba75fdd1e9346e9fcd74b0e39 Mon Sep 17 00:00:00 2001 From: Chris Antos Date: Fri, 22 Jan 2021 19:18:47 -0800 Subject: [PATCH] Fixed #60; completion fails with multiple slashes. Normalizing paths in generators is problematic; if normalizing happens, it should happen during match insertion. Comparing input vs matches needs to advance past adjacent path separators so that "\\\\" is considered equal to "\". --- clink/core/include/core/match_wild.h | 9 +++++++++ clink/core/include/core/path.h | 2 ++ clink/core/include/core/str_compare.h | 11 +++++++++++ clink/core/src/globber.cpp | 2 +- clink/core/src/path.cpp | 17 +++++++++++++++++ clink/lib/src/file_match_generator.cpp | 2 +- clink/lib/test/file.cpp | 13 +++++++++++++ 7 files changed, 54 insertions(+), 2 deletions(-) diff --git a/clink/core/include/core/match_wild.h b/clink/core/include/core/match_wild.h index 9b890febc..deeee3797 100644 --- a/clink/core/include/core/match_wild.h +++ b/clink/core/include/core/match_wild.h @@ -175,6 +175,15 @@ bool match_wild_impl(const str_iter_impl& _pattern, const str_iter_impl& _ pattern.next(); file.next(); symbol_matched = true; + // Advance past path separators (consider "\\\\" and "\" equal). + assert(path::is_separator(c) == path::is_separator(d)); + if (path::is_separator(c)) + { + while (path::is_separator(pattern.peek())) + pattern.next(); + while (path::is_separator(file.peek())) + file.next(); + } break; } } diff --git a/clink/core/include/core/path.h b/clink/core/include/core/path.h index b018a8671..166530250 100644 --- a/clink/core/include/core/path.h +++ b/clink/core/include/core/path.h @@ -14,6 +14,8 @@ void refresh_pathext(); void normalise(str_base& in_out, int sep=0); void normalise(char* in_out, int sep=0); +void normalise_separators(str_base& in_out, int sep=0); +void normalise_separators(char* in_out, int sep=0); bool is_separator(int c); const char* next_element(const char* in); bool get_base_name(const char* in, str_base& out); diff --git a/clink/core/include/core/str_compare.h b/clink/core/include/core/str_compare.h index 5732a5c15..c6e245e75 100644 --- a/clink/core/include/core/str_compare.h +++ b/clink/core/include/core/str_compare.h @@ -4,6 +4,7 @@ #pragma once #include "base.h" +#include "path.h" #include "str_iter.h" #include @@ -82,6 +83,16 @@ int str_compare_impl(str_iter_impl& lhs, str_iter_impl& rhs) lhs.next(); rhs.next(); + + // Advance past path separators (consider "\\\\" and "\" equal). + assert((c == '/') == (d == '/')); + if (c == '/') + { + while (path::is_separator(lhs.peek())) + lhs.next(); + while (path::is_separator(rhs.peek())) + rhs.next(); + } } if (lhs.more() || rhs.more()) diff --git a/clink/core/src/globber.cpp b/clink/core/src/globber.cpp index ee76100ba..c35982141 100644 --- a/clink/core/src/globber.cpp +++ b/clink/core/src/globber.cpp @@ -45,7 +45,7 @@ globber::globber(const char* pattern) m_handle = nullptr; path::get_directory(pattern, m_root); - path::normalise(m_root.data()); + path::normalise_separators(m_root.data()); } //------------------------------------------------------------------------------ diff --git a/clink/core/src/path.cpp b/clink/core/src/path.cpp index a9683862d..f2295d6da 100644 --- a/clink/core/src/path.cpp +++ b/clink/core/src/path.cpp @@ -192,6 +192,23 @@ void normalise(char* in_out, int sep) *write = '\0'; } +//------------------------------------------------------------------------------ +void normalise_separators(str_base& in_out, int sep) +{ + normalise_separators(in_out.data(), sep); +} + +//------------------------------------------------------------------------------ +void normalise_separators(char* in_out, int sep) +{ + if (!sep) + sep = PATH_SEP[0]; + + for (char* next = in_out; *next; next++) + if (is_separator(*next) && *next != sep) + *next = sep; +} + //------------------------------------------------------------------------------ bool is_separator(int c) { diff --git a/clink/lib/src/file_match_generator.cpp b/clink/lib/src/file_match_generator.cpp index b256ddab2..d20877ae6 100644 --- a/clink/lib/src/file_match_generator.cpp +++ b/clink/lib/src/file_match_generator.cpp @@ -45,7 +45,7 @@ static class : public match_generator free(expanded_root); } - path::normalise(root); + path::normalise_separators(root); root << "*"; diff --git a/clink/lib/test/file.cpp b/clink/lib/test/file.cpp index 199ee89c8..8cb4d5e33 100644 --- a/clink/lib/test/file.cpp +++ b/clink/lib/test/file.cpp @@ -89,4 +89,17 @@ TEST_CASE("File match generator") tester.set_expected_matches("m:only", "m:file1", "m:file2"); tester.run(); } + + SECTION("redundant separators") + { + tester.set_input("dir1\\\\\\" DO_COMPLETE); + tester.set_expected_matches("dir1\\only", "dir1\\file1", "dir1\\file2"); + tester.set_expected_output("dir1\\"); + tester.run(); + + tester.set_input("dir1\\\\\\f" DO_COMPLETE); + tester.set_expected_matches("dir1\\file1", "dir1\\file2"); + tester.set_expected_output("dir1\\file"); + tester.run(); + } }