= raidgrep(1)
:doctype: manpage
:man source: raidgrep
:man manual: raidgrep manpage
:toc:
:homepage: https://gitlab.com/dunj3/raidgrep

== NAME
raidgrep - A search tool for Guild Wars 2/arcdps log files.

== SYNOPSIS
*raidgrep* ['-OPTION' ['...']] ['--' ['-PREDICATE' ['...']]]

== DESCRIPTION
raidgrep is a CLI search tool to search through .evtc log files generated by
arcdps (a Guild Wars 2 addon).

raidgrep was inspired by other search tools - namely +ripgrep+ and +find+ - but
has support for reading and parsing the binary files produced by arcdps and
applying Guild Wars 2 specific filters.

== OPTIONS

The following options have to be given before any filters are given on the
command line:

*--debug*::
    Print more debugging information to stderr.

*-l*, *--files-with-matches*::
    Only show the name of matching files.

*--guilds*::
    Load guild information from the API. +
    +
    Loading guild information requires network access and slows down the
    program considerably, so this is disabled by default.

*--no-color*::
    Disable colored output.

*--repl*::
    Run the REPL.

*-V*, *--version*::
    Prints version information.

*-d* 'path', *--dir* 'path'::
    Path to the folder with logs [default: .]

*-s* 'sorting', *--sort* 'sorting'::
    Sort the output according to the given fields. Valid fields are 'boss',
    'date', 'cm' and 'outcome'. Fields can be comma-separated, then later
    fields are used to break ties. Fields can be prefixed by ~ to indicate
    sorting in the opposite direction. +
    +
    Note that using this option will cause raidgrep to buffer all results until
    the search has finished, which means that no output will happen until every
    file has been searched. It can also lead to a higher memory consumption,
    based on how many logs are matched. Therefore, it is advised that you do
    not use this option unless needed. +

== PREDICATES

The following predicates can be used after the options. Note that they should
be preceeded by a +--+ on the command line, to signal the parser to switch from
parsing options to parsing predicates.

=== Predicate Combinators

'A' [*and*] 'B'::
    Match the log only if both 'A' and 'B' are matching. The *and* is optional,
    predicates written after each other are implicitely joined with *and*.

'A' *or* 'B'::
    Match the log if 'A' or 'B' are matching.

*not* 'PREDICATE'::
    Match the log only if the given predicate does not match.

*(* 'PREDICATE' *)*::
    Parenthesis can be used to group predicates to enforce the correct operator
    ordering.

=== Log Predicates

Those predicates can be used as-is in the filter:

*-success*::
    Include logs that are successful.

*-wipe*::
    Include logs that are failed.

*-outcome* 'OUTCOMES'::
    Include logs with the given outcomes. Outcomes are 'success', 'wipe', or a
    comma-separated combination thereof.

*-weekday* 'WEEKDAYS'::
    Include logs made on the given weekdays. Weekdays are given either fully or
    as a 3-letter-abbreviation and can be combined by commas.

*-before* 'DATE'::
    Include logs made before the given date. Date can be either in
    "year-month-day" or "year-month-day hour:minute:second" format.

*-after* 'DATE'::
    Include logs made after the given date. See *-before* for valid date
    formats.

*-log-before* 'DATE', *-log-after* 'DATE'::
    Same as *-before* and *-after*, but does not use file name heuristics to
    filter the date. +
    +
    This can fix wrong results in case you renamed files, but it comes at the
    cost of worse runtime performance. You should always use *-before*/*-after*
    when possible!

*-boss* 'BOSSES'::
    Include logs from the given bosses. See below for a list of valid boss
    names. Names can also be comma separated.

*-cm*::
    Include logs that were done with the Challenge Mote enabled.

*-player* 'REGEX'::
    Include logs in which at least one player's account or character name
    matches the given regex. +
    +
    Note that you have to quote the regex if it contains spaces or other special characters.

*all(player:* 'PREDICATES' *)*::
    Include logs in which all players match the given player predicates. See
    below for a list of player predicates.

*any(player:* 'PREDICATES' *)*::
    Include logs in which any player matches the given player predicates. See
    below for a list of player predicates.

=== Player Predicates

The following predicates have to be wrapped in either a *any(player: ...)* or
*all(player: ...)* construct to be accepted.

*-character* 'REGEX'::
    Matches the player if the character name matches the given regular
    expression.

*-account* 'REGEX'::
    Matches the player if the account name matches the given regular
    expression.

*-name* 'REGEX'::
    Shorthand that matches if the character or the account name match the given
    regular expression.

*-class* 'CLASSES'::
    Match the player if they have one of the given classes. Note that a core
    class won't match its elite specializations, so _Guardian_ won't match
    _Dragonhunter_. +
    +
    Names can be comma separated, in which case the player must have any of the
    listed classes.

=== Boss Names

Bosses can be referred to by their official name, although if that name
contains spaces it must be enclosed in quotes, and it's cumbersome to write.
Therefore, raidgrep also accepts a lot of shorthands that are established in
the community.

The following list is an inexhaustive list of all accepted boss names, with one
name per boss given:

* *Wing 1*: vg, gorseval, sabetha
* *Wing 2*: slothasor, matthias
* *Wing 3*: kc, xera
* *Wing 4*: cairn, mo, samarog, deimos
* *Wing 5*: desmina, dhuum
* *Wing 6*: ca, largos, qadim
* *Wing 7*: adina, sabir, qadimp
* *100 CM*: skorvald, artsariiv, arkk
* *99 CM*: mama, siax, ensolyss
* *Strike Missions*: icebrood, fraenir, kodans, boneskinner, whisper

=== Regular Expressions

raidgrep uses Rust's +regex+ library for regular expression support. A full
syntax reference can be found at https://docs.rs/regex/#syntax. A (very) short
primer is given here:

*foo*::
    Match foo literally.

*foo|bar*::
    Match either foo or bar.

*.*::
    Match any character.

*^*::
    Match the beginning of the string.

*$*::
    Match the end of the string.

=== A Note About Quoting

raidgrep uses its own parser to split and parse the given predicates. However,
when calling raidgrep from the command line, the shell also applies some
splitting. raidgrep tries to reconstruct the given predicates as good as
possible, but it does not always work.

This means that sometimes, predicates as described here may not work correctly
when used in the CLI argument. To circumvent this, there are multiple options:

* Use the raidgrep REPL, which is not subject to your shell's splitting.
* Pass the filter as a single big argument, which is usually achieved by
  enclosing it in quotes and escaping any quotes in the filter.

Most use cases should work without much adaption. If there is a case that looks
like it should work but doesn't, feel free to report it as a bug (see below).

== REPL

If given the *--repl* option, raidgrep will not start searching for logs and
instead enter a read-eval-print-loop. You can give it a predicate, it will
print the results and ask for the next predicate.

Any options given in this mode will apply to the whole REPL session. For
example, if started with *-l*, all REPL evaluations will only print the file
names of the matching files.

== EXIT STATUS

raidgrep will exit with status 0 (success) if at least one matching log was
found, with status 1 if no logs were found and status 2 if there was an error.

If used with the REPL mode, raidgrep will always exit with status 0.

== EXAMPLES

The following are examples of predicates as they might be entered in the REPL.
They can also be used on the command line, but proper escaping might have to be
applied (depending on your shell):

+-success -player Godric+::
    Find any logs that were successful and had a player called "Godric" in
    them.

+-wipe (-player Godric or -player Emma)+::
    Find any logs that were unsuccesful and had either a player called "Godric"
    or a player called "Emma" in them.

+-after 2020-01-01 any(player: -character Xenia)+::
    Find any logs after the 1st of January 2020 where a player had a character
    name matching "Xenia".

The following examples are raidgrep invocations that show how predicates can be
supplied as arguments to raidgrep:

`raidgrep -- -success -player Godric`::
    Same as above. Special quoting is not necessary, as raidgrep can figure out
    what the user meant.

`raidgrep -- -player "Godric Gobbledygook"`::
    Find any logs with a player called "Godric Gobbledygook". Raidgrep can
    figure out how the quotes were meant to be, even though the shell stripped
    them away.

`raidgrep -- 'all(player: -character "o{2}")'`::
    In this example, the whole command line is wrapped in single quotes, to
    prevent the shell from splitting it apart. This should work for most
    predicates.

== FILES

* '$XDG_CACHE_HOME/raidgrep': Temporary data.
* '$XDG_CONFIG_HOME/raidgrep/history': REPL history.

Note that 'XDG_CACHE_HOME' defaults to '\~/.cache' if unset, and
'XDG_CONFIG_HOME' defaults to '~/.config'.

== BUGS

Bugs and other issues are tracked in the Gitlab repository at
https://gitlab.com/dunj3/raidgrep/-/issues.

If you want to report a bug, you can either

* Open an issue in the aforementioned issue tracker
* Write an email to mailto:raidgrep@kingdread.de[]
* Contact me through Guild Wars 2: +Dunje.4863+

When reporting a bug, please include as much information as you can beforehand
- that includes the version of raidgrep that you are using, your operating
system and (if possible) the log file itself that raidgrep fails on.

== COPYRIGHT
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program.  If not, see <http://www.gnu.org/licenses/>.

== RESOURCES
* Source repository: https://gitlab.com/dunj3/raidgrep/
* Binary releases: https://kingdread.de/raidgrep/
* arcdps addon for Guild Wars 2: https://www.deltaconnected.com/arcdps/

== AUTHOR
*raidgrep* was written by Daniel Schadt.