screp: grep-like CLI using Parsec parsers instead of regex

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

screp is a grep-like command-line tool that uses Parsec parser combinators instead of regular expressions for pattern matching. Write patterns using a familiar Haskell-like DSL with combinators like 'some digit', 'string TODO', or 'manyTill anyChar (string END)'.


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.1.0.0
Change log None available
Dependencies base (>=4.19.0 && <5), containers (>=0.7 && <0.8), directory (>=1.3.8 && <1.4), filepath (>=1.5.4 && <1.6), optparse-applicative (>=0.14 && <0.19), parsec (>=3.1.18 && <3.2), process (>=1.6 && <1.7), scrappy-core (>=0.1.0.1 && <0.2), screp [details]
License BSD-3-Clause
Author Galen Sprout
Maintainer galen.sprout@gmail.com
Category Text, Console
Home page https://github.com/Ace-Interview-Prep/screp
Bug tracker https://github.com/Ace-Interview-Prep/screp/issues
Uploaded by lazyLambda at 2026-02-24T18:41:19Z

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for screp-0.1.0.0

[back to package description]

screp

A grep-like CLI that uses Parsec parser combinators instead of regex.

Installation

cabal build screp
cabal install screp

Make sure ~/.local/bin is in your PATH:

export PATH="$HOME/.local/bin:$PATH"

Or install from Hackage:

cabal install screp

Usage

screp PATTERN FILE...
screp [OPTIONS] PATTERN FILE...

DSL Primitives

Primitive Example Description
char char 'x' Single character
string string "abc" Literal string
anyChar anyChar Any character
digit digit 0-9
letter letter a-z, A-Z
alphaNum alphaNum Letter or digit
space space Single whitespace
spaces spaces Zero or more whitespace
newline newline Newline character
oneOf oneOf "abc" Match one of chars
noneOf noneOf "xyz" Match none of chars

DSL Combinators

Combinator Syntax Description
Sequence p1 >> p2 Run p1 then p2, return p2's result
Concat p1 <+> p2 Run both, concatenate results
Alternative p1 <|> p2 Try p1, else p2
Many many p Zero or more
Some some p One or more
Optional optional p Zero or one
Try try p Backtracking
Between between '(' ')' p Parse between delimiters
Count count 3 p Exactly n repetitions
ManyTill manyTill p end Non-greedy: match p until end
Ref ref "name" Named parser from import file

Examples

# Find digits
screp 'some digit' file.txt

# Find email patterns (inline)
screp 'some alphaNum <+> char '\''@'\'' <+> some alphaNum <+> char '\''.'\'' <+> some letter' contacts.txt

# Find TODO comments
screp 'string "TODO"' -r ./src/

# Search recursively with extension filter
screp -r -e .hs 'string "import"' ./src/

# Count matches
screp -c 'digit' data.txt

# JSON output
screp --json 'some digit' file.txt

# Non-greedy matching: find everything between X and Y
screp 'string "START" <+> manyTill anyChar (string "END")' file.txt

Using Custom Parsers (--import)

For complex patterns, define parsers in a Haskell file and reference them with ref:

Parsers.hs:

module Parsers (parsers) where

import Text.Parsec
import Text.Parsec.String
import Data.Map (Map)
import qualified Data.Map as Map

parsers :: Map String (Parser String)
parsers = Map.fromList
  [ ("email", email)
  , ("phone", phone)
  ]

email :: Parser String
email = do
  user <- many1 alphaNum
  char '@'
  domain <- many1 alphaNum
  char '.'
  tld <- many1 letter
  pure $ user ++ "@" ++ domain ++ "." ++ tld

phone :: Parser String
phone = do
  a <- count 3 digit
  char '-'
  b <- count 3 digit
  char '-'
  c <- count 4 digit
  pure $ a ++ "-" ++ b ++ "-" ++ c

Usage:

# Find emails using custom parser
screp --import Parsers.hs 'ref "email"' contacts.txt

# Find phone numbers
screp --import Parsers.hs 'ref "phone"' contacts.txt

Requirements for custom parsers:

Options

-r, --recursive      Search directories recursively
-e, --extension EXT  Only search files with extension (e.g., .hs, .txt)
-i, --import FILE    Haskell file with named parsers (for 'ref "name"')
-v, --verbose        Verbose output with full match text
-c, --count          Only print count of matches
-q, --quiet          Quiet mode (exit code only)
-m, --max-results N  Maximum number of results to show
--json               Output results as JSON

Output Format

Default output is grep-like:

file.txt:1:28:123
file.txt:2:5:test@example.com

Format: filepath:line:column:matched_text

Library API

The Scrappy.Grep.* modules expose: