Skip to content

Grep clone

This tutorial will be all about writing a simple grep clone in arc.

When completed our grep clone will be able to:

  • Accept a PATTERN to search for
  • Accept any number of FILES to search
  • Ouptut lines of the FILES that match the PATTERN to stdout, with coloring

1. Setup

To begin with we need to scaffold the project

Install arc if you haven't already

$ pip install arc-cli

And create a file called grep_clone.py that contains the following:

examples/grep_clone/1_grep_clone.py
import arc


@arc.command
def command():
    arc.print("hello there!")


command()
This is just some simple scaffolding to get us started. Run it to make sure eveything is in order.
$ python grep.py 
hello there!
$ python grep.py --help
USAGE
    grep.py [-h]

OPTIONS
    --help (-h)  Displays this help message

2. Arguments

Next, we're going to want to add arguments to the command. For now, we'll only be implementing the PATTERN and FILES arguments. All of grep's many flags will be left alone for now.

examples/grep_clone/2_grep_clone.py
import re
import arc
from arc import types


@arc.command
def command(pattern: re.Pattern, files: list[types.File.Read]):
    arc.print(pattern)
    arc.print(files)


command()
$ python grep.py ^[\\d+] docs/docs/index.md docs/docs/usage/intro.md
re.compile('^[\\d+]')
[<_io.TextIOWrapper name='docs/docs/index.md' mode='r' encoding='UTF-8'>, <_io.TextIOWrapper name='docs/docs/usage/intro.md' mode='r' encoding='UTF-8'>]

As you can see, we've already got a validated regex pattern, and file handles to each of the specified files.

3. Functionality

With type handling / data validation already out of the way, the implentation will be fairly straightfoward.

examples/grep_clone/3_grep_clone.py
import re
import arc
from arc import color
from arc.types import File


@arc.command
def grep(pattern: re.Pattern, files: list[File.Read]):
    for file in files:  # Iterate over all the files
        for line in file.readlines():  # Iterate over all the line in the file
            if match := pattern.search(line):  # check for a match
                # If there is a match, highlight it
                colored = pattern.sub(
                    color.fg.RED + match.group() + color.fx.CLEAR,
                    line,
                )
                arc.print(colored, end="")


grep()
Let's run this over a couple of arc's documentation files searching for references to arc
$ python grep.py arc docs/docs/index.md docs/docs/usage/intro.md
*arc* is a tool for building declarative, and highly extendable CLI applications for Python ^3.10.
*arc's* features include:
*arc* can be installed with pip
$ pip install arc-cli
    [source repo](https://github.com/seanrcollings/arc/tree/master/docs/examples)
Pretty cool, huh? *arc* will pull *all* of the information that it needs from your [function docstrings and parameter definitons.](usage/documentation-generation.md)
Check out the [Usage](./usage/intro.md) section for more information on how to use *arc*.
You can check out the [playground](https://arc-playground.seancollings.dev) to try out *arc* in your browser.
This intro serves as a quick starting off point to see some of *arc's* most useful features.
The simplest *arc* program would look like this
1. `#!python @arc.command` is a Python decorator that transforms a function into an *arc* command.
*arc* uses argument type hints for data validation / conversion. For example, say we want to write a command that can sum two numbers together:
if the input fails to validate, *arc* will report a user-friendly error for the type
- if a parameter does not specify a type, *arc* implicitly types it as `#!python str`.
- **All** builtin types are supported by *arc*, and many stdlib types
*arc* is easily configurable via the `#!python arc.configure()` function.
*View the [reference](../reference/config.md#arc.config.configure) for details on all the configuration options*