CsTextFinder

recursive, regex-based file-content search tool

Concept:

A recursive, regex-based file-content search tool written in C# (.NET 10). Given a root directory, a set of file extensions, and a regular expression, it walks the directory tree and prints every file whose content contains a match.

Packages:

The project is composed of four packages linked by project references in the solution.
PackageKindRole
CommandLine library Parses /Key [Value] or -Key [Value] command-line tokens into a key-value map
DirNav library Depth-first directory walker; fires Action<string> delegates for each directory and file
Output library Reads file content, tests it against a compiled regex, and writes matching results to the console
EntryPoint executable Application - wires the packages, parses options, and drives the search

Quick Start:

# 1. Build (from the CsTextFinder/ solution root)
dotnet build

# 2. Search the current directory tree for C# files containing "Action"
dotnet run --project EntryPoint -- /P . /p cs /r "Action"

# 3. Or run the built executable directly
EntryPoint/bin/Debug/net10.0/CsTextFinder.exe /P . /p cs /r "Action"

# Git Bash / MINGW users - use - prefix to avoid shell path expansion
dotnet run --project EntryPoint -- -P . -p cs -r "Action"

Command-Line Options:

Options accept either a / prefix (Windows / PowerShell / cmd) or a - prefix (bash / MINGW); both are equivalent.
OptionArgumentDefaultMeaning
/P path . Root directory for the search
/p extensions (all files) Comma-separated file extensions to include, e.g. cs,txt
/r regex . (any) Regular expression matched against file content
/s true/false true Recurse into subdirectories
/H true/false true true: print a directory only when it has a matching file (clean output). false: print every directory as it is entered (real-time progress).
/v (flag) off Print all resolved options before searching
/h (flag) off Print help and exit
Examples:
# Find all C# files containing "interface" under the solution root
CsTextFinder.exe /P . /p cs /r "interface"

# Search source and markdown files for a TODO comment, show all directories
CsTextFinder.exe /P . /p "cs,md" /r "TODO" /H false

# Verbose output - shows resolved path, extensions, and regex before searching
CsTextFinder.exe /P .. /p cs /r "Action" /v

Output:

Matching files are grouped under their containing directory:
  CsTextFinder ver 1.0.0
 ========================
  searching path: "."
  extensions: ["cs"]
  matching files with regex: "Action"

  ./DirNav
      "DirNav.cs"

  ./EntryPoint
      "Program.cs"

  2 files matched out of 12 visited in 4 dirs

  That's all Folks!
Directories that contain no matching files are hidden by default (/H true). Set /H false to print every directory as it is entered.

Design:

CommandLine

Parses raw args tokens into a dictionary of option keys to string values. A token starting with / or - is treated as a key; the next token (if it does not itself start with / or -) becomes its value, otherwise the value is set to "true".

DirNav

Depth-first directory walker. Callers register delegates:
Action<string> OnDir   // called when entering a directory
Action<string> OnFile  // called for each file whose extension is in the filter list
DirNav fires OnDir when entering each directory and OnFile for each matching file. Build-output and VCS directories (bin, obj, target, .git, .vs, etc.) are skipped automatically - never entered.

Output

Holds a compiled Regex instance and exposes OnDir(string path) and OnFile(string path) methods that match the DirNav delegate signatures. OnFile reads the file content with File.ReadAllText and applies Regex.IsMatch. When a match is found the filename is printed; the containing directory header is buffered and flushed on the first match (implementing the hide-empty-dirs logic for /H true).

EntryPoint (Program.cs)

Wires the three libraries together. Program.cs parses options via CmdLine, constructs an Output instance with the resolved regex, then constructs a DirNav instance and registers output.OnDir and output.OnFile as the walk delegates before starting the traversal. The three libraries never reference each other - all coupling flows through EntryPoint.

Hide/show directory logic

When /H true (the default), a directory header is buffered rather than printed immediately. It is flushed to output only when the first matching file in that directory is found. Directories with no matches are never printed.

Building the Project:

The solution requires the .NET 10 SDK:
# Verify SDK version
dotnet --version    # should show 10.x

# Build all projects (from the CsTextFinder/ solution root)
dotnet build

# Build Release configuration
dotnet build -c Release

# Run directly from source
dotnet run --project EntryPoint -- /P . /p cs /r "TODO"

# Clean build outputs
dotnet clean
The self-contained executable is written to EntryPoint/bin/Debug/net10.0/CsTextFinder.exe (or EntryPoint/bin/Release/net10.0/CsTextFinder.exe for Release builds).

Testing:

# Functional smoke test - search this repo for all C# files containing "Action"
cd CsTextFinder
dotnet run --project EntryPoint -- /P . /p cs /r "Action" /v

# Search for interface definitions
dotnet run --project EntryPoint -- /P . /p cs /r "interface\s+I\w+"

# Test /H false (real-time directory output)
dotnet run --project EntryPoint -- /P . /p cs /r "class" /H false

External Dependencies:

Namespace / TypeSourceUsed byPurpose
System.Text.RegularExpressions .NET BCL Output Compile and match regular expressions against file content
System.IO .NET BCL DirNav, Output Directory enumeration and file reading
All functionality uses the .NET Base Class Library only. No NuGet packages required.