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

[ bsd3, console, library, program, text ] [ Propose Tags ] [ Report a vulnerability ]

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]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.0
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
Uploaded by lazyLambda at 2026-02-24T18:41:42Z
Category Text, Console
Home page https://github.com/Ace-Interview-Prep/screp
Bug tracker https://github.com/Ace-Interview-Prep/screp/issues
Distributions
Executables screp
Downloads 2 total (2 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2026-02-24 [all 1 reports]

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:

  • Module must export parsers :: Map String (Parser String)
  • Requires parsec and containers packages installed

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:

  • Scrappy.Grep.DSL - AST types (ParserExpr, MatchResult)
  • Scrappy.Grep.DSL.Parser - Parse DSL strings to AST
  • Scrappy.Grep.DSL.Interpreter - Convert AST to Parsec parsers
  • Scrappy.Grep.Search - File/directory search functions
  • Scrappy.Grep.Config - External parser execution via runghc
  • Scrappy.Grep.Output - Result formatting