Comparison Story: CppTextFinder

1. Introduction — recursive, regex-based file-content search in C++23

1.  Introduction

CppTextFinder is a command-line tool that walks a directory tree and reports files whose content matches a regular expression. It is written in C++23 with named modules and built with CMake 3.28+. Alongside the Rust, C#, and Python variants it forms a controlled cross-language comparison of the same three-component architecture.

1.1  Features

  • Regex search over file contents (text and binary files).
  • Recursive or single-directory walk.
  • File-extension filtering (e.g. search only .cpp, .h).
  • Built-in skip list: build artifacts and VCS directories are never entered.
  • Two output modes controlled by /H: real-time traversal vs. clean match-only output.
  • Summary line: files visited and files matched.

1.2  Parts

The project is composed of four independent parts. The three libraries never import one another — all composition happens in EntryPoint, which imports all three modules and wires them together with std::function callbacks.
Part Kind Role
CommandLine static library export module cmd_line; — parses /Key [Value] or -Key [Value] command-line arguments.
DirNav static library export module dir_nav; — event-driven depth-first directory walker using std::filesystem.
Output static library export module output; — regex match against file content and grouped stdout emission.
EntryPoint executable (text_finder) Application — imports the three modules and wires them via lambda callbacks.
CommandLine   DirNav   Output
      \          |       /
       \         |      /
        \        |     /
             EntryPoint
                │
                ▼
          text_finder (executable)

1.3  Quick Start

# Windows / Visual Studio 2022
cmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release

# The text_finder executable is placed under build/EntryPoint/Release/
./build/EntryPoint/Release/text_finder /P . /p .cpp /r "std::regex"
# Linux / macOS with Ninja
cmake -S . -B build -G Ninja
cmake --build build

./build/EntryPoint/text_finder -P . -p .cpp -r "std::regex"

1.4  Command-Line Options

Options accept either a / prefix (Windows / PowerShell) or a - prefix (bash / Unix); both are equivalent. Any option that appears on the command line without a following value receives the value "true".
Option Argument Default Meaning
/P path . Root directory for the search
/p extensions (all files) Comma-separated extensions, e.g. .cpp,.h
/r regex . (any) Regular expression matched against file content
/s true/false true Recurse into subdirectories
/H true/false true Hide directories that contain no matching files
/v (flag) off Verbose — echo all options before searching
/h (flag) off Print help and exit
Git Bash / MINGW note: the shell converts /P, /r, etc. to Windows paths. Prefix with MSYS_NO_PATHCONV=1 to suppress this, or use the - form. PowerShell and cmd.exe do not have this issue.

1.5  Examples

# Find all .cpp files containing "std::regex" under the current tree
text_finder /P . /p .cpp /r "std::regex"

# Search .cpp and .h files for a TODO comment, show all directories
text_finder /P . /p .cpp,.h /r "TODO" /H false

# Verbose output — shows resolved options before searching
text_finder /P .. /p .cpp /r "int main" /v

1.6  Skip List

DirNav maintains a hard-coded skip list of directory names that are never entered during traversal. Entries are matched against the bare directory name, so a build folder at any depth is skipped regardless of where it appears.
Category Skipped directory names
Build artifacts bin, obj (C#); target (Rust); build, out (C++)
Python __pycache__, .venv, venv, dist
VCS / IDE .git, .vs, .idea
Archives archive

1.7  Design at a Glance

The next four pages walk through the design and full source of each part in composition order:
Page Focus
2. CommandLine CmdLine class — argv into std::unordered_map<std::string, std::string> with dual / / - prefix support.
3. DirNav DirNav depth-first walker driven by std::function callbacks; baked-in skip list.
4. Output Output class — std::regex match against file content, grouped stdout emission, lazy directory printing.
5. EntryPoint main.cpp — imports the three modules and wires them via lambda callbacks.
6. Conclusion Sample output, build & test commands, design takeaways, and references.
Two design threads run through every part. First, no library imports another library or the executable; all composition happens in EntryPoint, which registers lambda callbacks that adapt Output's methods to DirNav's callback signatures. Second, C++23 named modules replace headers entirely — each library's .ixx file both declares and defines its public API, and consumers write import cmd_line; instead of #include "CmdLine.h".