Skip to content
30 changes: 22 additions & 8 deletions std/file.d
Original file line number Diff line number Diff line change
Expand Up @@ -4617,7 +4617,8 @@ enum SpanMode
["animals", "plants"]));
}

private struct DirIteratorImpl
private struct DirIteratorImpl(alias pred = (scope ref DirEntry entry) => true)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
{
@safe:
SpanMode _mode;
Expand Down Expand Up @@ -4721,6 +4722,8 @@ private struct DirIteratorImpl

bool mayStepIn()
{
if (!pred(_cur))
return false;
return _followSymlink ? _cur.isDir : _cur.isDir && !_cur.isSymlink;
}
}
Expand Down Expand Up @@ -4780,6 +4783,8 @@ private struct DirIteratorImpl

bool mayStepIn()
{
if (!pred(_cur))
return false;
return _followSymlink ? _cur.isDir : attrIsDir(_cur.linkAttributes);
}
}
Expand Down Expand Up @@ -4864,16 +4869,17 @@ private struct DirIteratorImpl
}
}

struct _DirIterator(alias pred = (scope ref DirEntry entry) => true, bool useDIP1000)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
// Must be a template, because the destructor is unsafe or safe depending on
// whether `-preview=dip1000` is in use. Otherwise, linking errors would
// result.
struct _DirIterator(bool useDIP1000)
{
static assert(useDIP1000 == dip1000Enabled,
"Please don't override useDIP1000 to disagree with compiler switch.");

private:
SafeRefCounted!(DirIteratorImpl, RefCountedAutoInitialize.no) impl;
SafeRefCounted!(DirIteratorImpl!(pred), RefCountedAutoInitialize.no) impl;

this(string pathname, SpanMode mode, bool followSymlink) @trusted
{
Expand All @@ -4887,7 +4893,7 @@ public:

// This has the client code to automatically use and link to the correct
// template instance
alias DirIterator = _DirIterator!dip1000Enabled;
alias DirIterator = _DirIterator!((scope ref DirEntry entry) => true, dip1000Enabled);

/++
Returns an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
Expand Down Expand Up @@ -4975,10 +4981,11 @@ foreach (d; dFiles)

// For some reason, doing the same alias-to-a-template trick as with DirIterator
// does not work here.
auto dirEntries(bool useDIP1000 = dip1000Enabled)
auto dirEntries(alias pred = (scope ref DirEntry entry) => true, bool useDIP1000 = dip1000Enabled)
(string path, SpanMode mode, bool followSymlink = true)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
{
return _DirIterator!useDIP1000(path, mode, followSymlink);
return _DirIterator!(pred, useDIP1000)(path, mode, followSymlink);
}

/// Duplicate functionality of D1's `std.file.listdir()`:
Expand Down Expand Up @@ -5079,15 +5086,16 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled)
}

/// Ditto
auto dirEntries(bool useDIP1000 = dip1000Enabled)
auto dirEntries(alias pred = (scope ref DirEntry entry) => true, bool useDIP1000 = dip1000Enabled)
(string path, string pattern, SpanMode mode,
bool followSymlink = true)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
{
import std.algorithm.iteration : filter;
import std.path : globMatch, baseName;

bool f(DirEntry de) { return globMatch(baseName(de.name), pattern); }
return filter!f(_DirIterator!useDIP1000(path, mode, followSymlink));
return filter!f(_DirIterator!(pred, useDIP1000)(path, mode, followSymlink));
}

@safe unittest
Expand Down Expand Up @@ -5192,6 +5200,12 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled)
sort(result);

assert(equal(files, result));

import std.algorithm : endsWith;
auto result2 = dirEntries!((scope ref DirEntry entry) => entry.name.endsWith("Hello World"))(dir, SpanMode.shallow).map!((return a) => a.name.normalize()).array();
import std.stdio;
writeln(result2);
assert(result2.length == 1);
}

// https://issues.dlang.org/show_bug.cgi?id=21250
Expand Down