### ----------------------------------------------------
### -- App::Rak
### -- Licenses: Artistic-2.0
### -- Authors: Elizabeth Mattijsen
### -- File: resources/help/pattern.txt
### ----------------------------------------------------
Pattern specification:
‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒‒

There are 4 ways in which a primary pattern can be specified:

1. As the first positional argument
2. Or with the --pattern=foo argument
3. Or with the --not=foo argument
4. Or using the --patterns-from=file argument

The first is easiest for a quick ad-hoc search.  The second and third can
be handy if you want to create a short-cut to searching for (the absence
of) a particular string with --save.  The last one allows you set up a
set of patterns to be searched for simultaneously.

The --not=foo argument negates the match, so will select items that do
**NOT** match the pattern specification.

If the --patterns-from=file argument is specified, it will read the content
of the given file and process each line as a pattern specification, as
described below.  When searching, each pattern is tried on an item, and
accepted as soon as a pattern matched.  Any highlighting will occur on
any of the patterns specified.

If a literal string is specified as a pattern, then by default any item of
which the stringification contains that string, will be accepted.

Example:
# produce any lines that have "foo" in them
$ rak foo

Patterns come in 4 flavours:

1. as a literal string
2. as a regex (the Raku name for "regular expression")
3. as a piece of code (a Callable in Raku)
4. as a JSON path expression

Whether something you specified is interpreted as a regex or as code, or
just as a string, is determined by the --type argument.  By default, the
--type arguments assumes "auto".  When this is (implicitly) specified,
then the string will be checked for special markers to deduce the intended
type of pattern.

Regex:

If a string that starts and ends with '/' is specified as a pattern,
it is considered to be a regex and will be compiled as such.  Any
item of which the stringification smart matches with the regex,
will be accepted.  See https://docs.raku.org/language/regexes for
more information about Raku regexes.

Example:
# produce any lines that have the word "bar" in them
$ rak '/ << bar >> /'

If --type=regex has been specified, you should omit the '/' at either end of
the string:

Example:
# produce any lines that have the word "bar" in them
$ rak --type=regex '<< bar >>'

Code:

If a string that starts with '{' and ends with '}' is specified, or
a string that starts with '*', they will be considered to be Raku
executable code and compiled as such.  Each item will be passed as
a positional argument to the compiled code, available in its scope
as the topic (aka $_).  To facilitate the use of libraries that wish
to access that topic, it is also available as the $*_ dynamic variable.

The code is expected to return a value that is:

1. True       produce item, unless --invert-match was specified
2. False      do **NOT** produce item, unless --invert-match was specified
3. Empty      do **NOT** produce item, unless --invert-match was specified
4. Nil        do **NOT** produce item, unless --invert-match was specified
5. Slip       produce all items in the Slip, always
6. product    produce that, always

True or False are returned for any condition.

Empty is returned for any failed conditional construct, such as "if",
"unless", "with" or "without".

Nil is typically returned when a "try" has failed.

That last two options are specifically handy when using in conjunction
with the --unique, --frequencies (for getting summaries).  And with the
content modification options --modify-files and --rename-files.

Examples:
# produce any lines that have "foo" in them
$ rak '*.contains("foo")'

# produce any lines that do **NOT** have "foo" in them
$ rak '*.contains("foo").not'

# produce uppercased lines
$ rak '*.uc'

# produce only lines uppercased that have "foo" in them
$ rak '{ .uc if .contains("foo") }'

# produce all lines, only uppercase the ones that have "rakudoc" in them
$ rak '{.contains("rakudoc") ?? .uc !! $_}'

# produce all unique words
$ rak '*.words.Slip'

If --type=code has been specified, you should omit the '{' and '}', or
omit the initial '*'.

Examples:
# produce uppercased lines
$ rak --type=code .uc

# produce all lines, only uppercase the ones that have "rakudoc" in them
$ rak --type=code '.contains("rakudoc") ?? .uc !! $_'

JSON path:

Interpret the pattern as a JSON path if the pattern begins with 'jp:'.
Only makes sense when used together with --json-per-file, --json-per-line
or --json-per-elem.  Requires that the JSON::Path module is installed.

Examples:
# produce all unique "auth" fields
$ rak --json-per-file --unique jp:auth

# produce all unique fields in the "tags" array
$ rak --json-per-file --unique 'jp:tags[*]'

Alternately, one can specify the --type=json-path argument, in which case
the 'jp:' should be omitted:

Examples:
# produce all unique "auth" fields
$ rak --json-per-file --type=json-path --unique auth

# produce all unique fields in the "tags" array
$ rak --json-per-file --type=json-path --unique 'tags[*]'

The following syntax is supported

  $           root node
  .key        index hash key
  ['key']     index hash key
  [2]         index array element
  [0,1]       index array slice
  [4:5]       index array range
  [:5]        index from the beginning
  [-3:]       index to the end
  .*          index all elements
  [*]         index all elements
  [?(expr)]   filter on Raku expression
  ..key       search all descendants for hash key

A query that is not rooted from $ or specified using .. will be evaluated
from the document root (that is, same as an explicit $ at the start).

The "jp:path" and "--type=json-path" syntax are actually syntactic sugar
for calling a dedicated "jp" macro that takes a JSON path as its unquoted
argument, and returns an instantiated C<JP> object.

This means that:

  $ rak --json-per-file jp:foo
  $ rak --json-per-file --type=json-path foo

are a different way of saying:

  $ rak --json-per-file '{ jp(foo).Slip }'

using the "pattern is Raku code" syntax.

The following methods can be called on the "JP" object:

  .value             The first selected value.
  .values            All selected values as a Seq.
  .paths             The paths of all selected values as a Seq.
  .paths-and-values  Interleaved selected paths and values.

In all other ways, the "JP" object as a a "Seq" object.

Search types on literal strings:

Literal strings matching can be further specialized with other values of the
--type argument:

 - contains     string must occur anywhere in item
 - words        string must be surrounded by (virtual) whitespace in item
 - starts-with  item must *start* with string
 - ends-with    item must *end* with string
 - equal        item must be *equal* to string
 - split        split string on whitespace for separate patterns

Examples:
# produce any lines that have the word "bar" in them
$ rak --type=words bar

# produce any lines that start with "Example"
$ rak --type=starts-with Example

Both literal string matching, as well as matching with a regex, are
sensitive to the --smartcase, --ignorecase and --ignoremark arguments.

Shortcuts:

Several shortcuts are available to indicate some type of behaviour for
literal strings.  They are

 - string      --type=contains string
 - §string     --type=words string
 - ^string     --type=starts-with string
 - string$     --type=ends-with string
 - ^string$    --type=equal string
 - !string     --type=not

Examples:
# produce any lines that have the word "bar" in them
$ rak §bar

# produce any lines that start with "Example"
$ rak ^Example

Additional patterns:

You can also specify additional patterns that should also (not) match:

 - --and=bar      Must ALSO match anywhere in line
 - --andnot=bar   Must ALSO NOT match anywhere in line
 - --or=bar       May ALSO match anywhere in line
 - --ornot=bar    May ALSO NOT match annywhere in line

Examples:
# produce any lines that have the words "foo" and "bar" in them
$ rak §foo --and=§bar

# produce any lines that start with "foo" but not have "bar" in them
$ rak ^foo --andnot=bar


